xref: /petsc/src/dm/impls/plex/plexegads.c (revision 03047865b8d8757cf1cf9cda45785c1537b01dc1) !
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 
DMPlex_EGADS_GeomDecode_Internal(const PetscInt geomClass,const PetscInt geomType,char ** retClass,char ** retType)255552b385SBrandon PetscErrorCode DMPlex_EGADS_GeomDecode_Internal(const PetscInt geomClass, const PetscInt geomType, char **retClass, char **retType)
26d71ae5a4SJacob Faibussowitsch {
275552b385SBrandon   PetscFunctionBeginHot;
285552b385SBrandon   /* EGADS Object Type */
29ac530a7eSPierre Jolivet   if (geomClass == CONTXT) *retClass = (char *)"CONTEXT";
30ac530a7eSPierre Jolivet   if (geomClass == TRANSFORM) *retClass = (char *)"TRANSFORM";
31ac530a7eSPierre Jolivet   if (geomClass == TESSELLATION) *retClass = (char *)"TESSELLATION";
32ac530a7eSPierre Jolivet   if (geomClass == NIL) *retClass = (char *)"NIL";
33ac530a7eSPierre Jolivet   if (geomClass == EMPTY) *retClass = (char *)"EMPTY";
34ac530a7eSPierre Jolivet   if (geomClass == REFERENCE) *retClass = (char *)"REFERENCE";
35ac530a7eSPierre Jolivet   if (geomClass == PCURVE) *retClass = (char *)"PCURVE";
36ac530a7eSPierre Jolivet   if (geomClass == CURVE) *retClass = (char *)"CURVE";
37ac530a7eSPierre Jolivet   if (geomClass == SURFACE) *retClass = (char *)"SURFACE";
38ac530a7eSPierre Jolivet   if (geomClass == NODE) *retClass = (char *)"NODE";
39ac530a7eSPierre Jolivet   if (geomClass == EDGE) *retClass = (char *)"EDGE";
40ac530a7eSPierre Jolivet   if (geomClass == LOOP) *retClass = (char *)"LOOP";
41ac530a7eSPierre Jolivet   if (geomClass == FACE) *retClass = (char *)"FACE";
42ac530a7eSPierre Jolivet   if (geomClass == SHELL) *retClass = (char *)"SHELL";
43ac530a7eSPierre Jolivet   if (geomClass == BODY) *retClass = (char *)"BODY";
44ac530a7eSPierre Jolivet   if (geomClass == MODEL) *retClass = (char *)"MODEL";
455552b385SBrandon 
465552b385SBrandon   /* PCURVES & CURVES */
475552b385SBrandon   if (geomClass == PCURVE || geomClass == CURVE) {
48ac530a7eSPierre Jolivet     if (geomType == LINE) *retType = (char *)"LINE";
49ac530a7eSPierre Jolivet     if (geomType == CIRCLE) *retType = (char *)"CIRCLE";
50ac530a7eSPierre Jolivet     if (geomType == ELLIPSE) *retType = (char *)"ELLIPSE";
51ac530a7eSPierre Jolivet     if (geomType == PARABOLA) *retType = (char *)"PARABOLA";
52ac530a7eSPierre Jolivet     if (geomType == HYPERBOLA) *retType = (char *)"HYPERBOLA";
53ac530a7eSPierre Jolivet     if (geomType == TRIMMED) *retType = (char *)"TRIMMED";
54ac530a7eSPierre Jolivet     if (geomType == BEZIER) *retType = (char *)"BEZIER";
55ac530a7eSPierre Jolivet     if (geomType == BSPLINE) *retType = (char *)"BSPLINE";
56ac530a7eSPierre Jolivet     if (geomType == OFFSET) *retType = (char *)"OFFSET";
575552b385SBrandon   }
585552b385SBrandon 
595552b385SBrandon   /* SURFACE */
605552b385SBrandon   if (geomClass == SURFACE) {
61ac530a7eSPierre Jolivet     if (geomType == PLANE) *retType = (char *)"PLANE";
62ac530a7eSPierre Jolivet     if (geomType == SPHERICAL) *retType = (char *)"SPHERICAL";
63ac530a7eSPierre Jolivet     if (geomType == CYLINDRICAL) *retType = (char *)"CYLINDRICAL";
64ac530a7eSPierre Jolivet     if (geomType == REVOLUTION) *retType = (char *)"REVOLUTION";
65ac530a7eSPierre Jolivet     if (geomType == TOROIDAL) *retType = (char *)"TOROIDAL";
66ac530a7eSPierre Jolivet     if (geomType == CONICAL) *retType = (char *)"CONICAL";
67ac530a7eSPierre Jolivet     if (geomType == EXTRUSION) *retType = (char *)"EXTRUSION";
68ac530a7eSPierre Jolivet     if (geomType == BEZIER) *retType = (char *)"BEZIER";
69ac530a7eSPierre Jolivet     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) {
74ac530a7eSPierre Jolivet     if (geomType == SREVERSE) *retType = (char *)"SREVERSE";
75ac530a7eSPierre Jolivet     if (geomType == NOMTYPE) *retType = (char *)"NOMTYPE";
76ac530a7eSPierre Jolivet     if (geomType == SFORWARD && geomClass == FACE) *retType = (char *)"SFORWARD";
77ac530a7eSPierre Jolivet     if (geomType == ONENODE && geomClass == EDGE) *retType = (char *)"ONENODE";
78ac530a7eSPierre Jolivet     if (geomType == TWONODE) *retType = (char *)"TWONODE";
79ac530a7eSPierre Jolivet     if (geomType == OPEN) *retType = (char *)"OPEN";
80ac530a7eSPierre Jolivet     if (geomType == CLOSED) *retType = (char *)"CLOSED";
81ac530a7eSPierre Jolivet     if (geomType == DEGENERATE) *retType = (char *)"DEGENERATE";
82ac530a7eSPierre Jolivet     if (geomType == WIREBODY) *retType = (char *)"WIREBODY";
83ac530a7eSPierre Jolivet     if (geomType == FACEBODY) *retType = (char *)"FACEBODY";
84ac530a7eSPierre Jolivet     if (geomType == SHEETBODY) *retType = (char *)"SHEETBODY";
85ac530a7eSPierre Jolivet     if (geomType == SOLIDBODY) *retType = (char *)"SOLIDBODY";
865552b385SBrandon   }
875552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
885552b385SBrandon }
895552b385SBrandon 
DMPlex_EGADS_EDGE_XYZtoUV_Internal(const PetscScalar coords[],ego obj,const PetscScalar range[],const PetscInt v,const PetscInt dE,PetscScalar paramsV[])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 
DMPlex_Geom_EDGE_XYZtoUV_Internal(const PetscScalar coords[],ego obj,const PetscScalar range[],const PetscInt v,const PetscInt dE,PetscScalar paramsV[],PetscBool islite)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 
DMPlex_EGADS_FACE_XYZtoUV_Internal(const PetscScalar coords[],ego obj,const PetscScalar range[],const PetscInt v,const PetscInt dE,PetscScalar paramsV[])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];
3133a7d0413SPierre Jolivet     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 
DMPlex_Geom_FACE_XYZtoUV_Internal(const PetscScalar coords[],ego obj,const PetscScalar range[],const PetscInt v,const PetscInt dE,PetscScalar paramsV[],PetscBool islite)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];
4153a7d0413SPierre Jolivet     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 
DMSnapToGeomModel_EGADS_Internal(DM dm,PetscInt p,ego model,PetscInt bodyID,PetscInt faceID,PetscInt edgeID,const PetscScalar mcoords[],PetscScalar gcoords[],PetscBool islite)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;
486bfe80ac4SPierre 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 
DMSnapToGeomModel_EGADS(DM dm,PetscInt p,PetscInt dE,const PetscScalar mcoords[],PetscScalar gcoords[])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 
5992a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &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)
DMPlexGeomPrintModel_Internal(ego model,PetscBool islite)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 
710bfe80ac4SPierre 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));
7843a7d0413SPierre Jolivet               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 
7903a7d0413SPierre Jolivet             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 
8063a7d0413SPierre Jolivet             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];
8262a8381b2SBarry Smith               int    unused;
8277bee2925SMatthew Knepley 
8285552b385SBrandon               if (islite) {
8292a8381b2SBarry Smith                 PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &unused, &mobjs, &senses));
8305552b385SBrandon                 id = EGlite_indexBodyTopo(body, vertex);
8315552b385SBrandon               } else {
8322a8381b2SBarry Smith                 PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &unused, &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 
DMPlexEGADSDestroy_Private(PetscCtxRt context)8472a8381b2SBarry Smith static PetscErrorCode DMPlexEGADSDestroy_Private(PetscCtxRt context)
848d71ae5a4SJacob Faibussowitsch {
8492a8381b2SBarry Smith   if (*(void **)context) EG_deleteObject((ego) * (void **)context);
850b6555650SPierre Jolivet   return PETSC_SUCCESS;
8515552b385SBrandon }
8525552b385SBrandon 
DMPlexEGADSClose_Private(PetscCtxRt context)8532a8381b2SBarry Smith static PetscErrorCode DMPlexEGADSClose_Private(PetscCtxRt context)
8545552b385SBrandon {
8552a8381b2SBarry Smith   if (*(void **)context) EG_close((ego) * (void **)context);
856b6555650SPierre Jolivet   return PETSC_SUCCESS;
8575552b385SBrandon }
8585552b385SBrandon 
DMPlexEGADSliteDestroy_Private(PetscCtxRt context)8592a8381b2SBarry Smith PetscErrorCode DMPlexEGADSliteDestroy_Private(PetscCtxRt context)
8605552b385SBrandon {
8612a8381b2SBarry Smith   if (*(void **)context) EGlite_deleteObject((ego) * (void **)context);
862b6555650SPierre Jolivet   return PETSC_SUCCESS;
8637bee2925SMatthew Knepley }
8647bee2925SMatthew Knepley 
DMPlexEGADSliteClose_Private(PetscCtxRt context)8652a8381b2SBarry Smith PetscErrorCode DMPlexEGADSliteClose_Private(PetscCtxRt context)
866d71ae5a4SJacob Faibussowitsch {
8672a8381b2SBarry Smith   if (*(void **)context) EGlite_close((ego) * (void **)context);
868b6555650SPierre Jolivet   return PETSC_SUCCESS;
8695552b385SBrandon }
8705552b385SBrandon 
DMPlexCreateGeom_Internal(MPI_Comm comm,ego context,ego model,DM * newdm,PetscBool islite)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 
892*21789920SBarry Smith     /*
893f0b74427SPierre Jolivet       Generate PETSc DMPlex
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));
9493a7d0413SPierre Jolivet           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];
10122a8381b2SBarry Smith         int    unused;
10137bee2925SMatthew Knepley 
10145552b385SBrandon         if (islite) {
10152a8381b2SBarry Smith           PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &unused, &mobjs, &senses));
10165552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
10175552b385SBrandon         } else {
10182a8381b2SBarry Smith           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &unused, &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);
1227ac530a7eSPierre Jolivet         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) {
13033a7d0413SPierre Jolivet               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;
1467b6555650SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
14687bee2925SMatthew Knepley }
1469c1cad2e7SMatthew G. Knepley 
DMPlexCreateGeom(MPI_Comm comm,ego context,ego model,DM * newdm,PetscBool islite)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) {
1491f0b74427SPierre Jolivet     // Generate PETSc DMPlex
1492c1cad2e7SMatthew G. Knepley     //  Get all Nodes in model, record coordinates in a correctly formatted array
1493c1cad2e7SMatthew G. Knepley     //  Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
1494c1cad2e7SMatthew G. Knepley     //  We need to uniformly refine the initial geometry to guarantee a valid mesh
1495c1cad2e7SMatthew G. Knepley 
1496d5b43468SJose E. Roman     // Calculate cell and vertex sizes
14975552b385SBrandon     if (islite) {
14985552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
14995552b385SBrandon     } else {
15009566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
15015552b385SBrandon     }
15029566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&edgeMap));
15039566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyIndexMap));
15049566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyVertexMap));
15059566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyEdgeMap));
15069566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyEdgeGlobalMap));
15079566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyFaceMap));
1508c1cad2e7SMatthew G. Knepley 
1509c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
1510c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
1511c1cad2e7SMatthew G. Knepley       int           Nf, Ne, Nv;
1512c1cad2e7SMatthew G. Knepley       PetscHashIter BIiter, BViter, BEiter, BEGiter, BFiter, EMiter;
1513c1cad2e7SMatthew G. Knepley       PetscBool     BIfound, BVfound, BEfound, BEGfound, BFfound, EMfound;
1514c1cad2e7SMatthew G. Knepley 
15159566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyIndexMap, b, &BIiter, &BIfound));
15169566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
15179566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
15189566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
15199566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
1520c1cad2e7SMatthew G. Knepley 
15219566063dSJacob Faibussowitsch       if (!BIfound) PetscCall(PetscHMapISet(bodyIndexMap, b, numFaces + numEdges + numVertices));
15229566063dSJacob Faibussowitsch       if (!BVfound) PetscCall(PetscHMapISet(bodyVertexMap, b, numVertices));
15239566063dSJacob Faibussowitsch       if (!BEfound) PetscCall(PetscHMapISet(bodyEdgeMap, b, numEdges));
15249566063dSJacob Faibussowitsch       if (!BEGfound) PetscCall(PetscHMapISet(bodyEdgeGlobalMap, b, edgeCntr));
15259566063dSJacob Faibussowitsch       if (!BFfound) PetscCall(PetscHMapISet(bodyFaceMap, b, numFaces));
1526c1cad2e7SMatthew G. Knepley 
15275552b385SBrandon       if (islite) {
15285552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15295552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15305552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
15315552b385SBrandon         EGlite_free(fobjs);
15325552b385SBrandon         EGlite_free(eobjs);
15335552b385SBrandon         EGlite_free(nobjs);
15345552b385SBrandon       } else {
15359566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15369566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1538c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1539c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
1540c1cad2e7SMatthew G. Knepley         EG_free(nobjs);
15415552b385SBrandon       }
1542c1cad2e7SMatthew G. Knepley 
1543c1cad2e7SMatthew G. Knepley       // Remove DEGENERATE EDGES from Edge count
15445552b385SBrandon       if (islite) {
15455552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15465552b385SBrandon       } else {
15479566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15485552b385SBrandon       }
15495552b385SBrandon 
1550c1cad2e7SMatthew G. Knepley       int Netemp = 0;
1551c1cad2e7SMatthew G. Knepley       for (int e = 0; e < Ne; ++e) {
1552c1cad2e7SMatthew G. Knepley         ego edge = eobjs[e];
1553c1cad2e7SMatthew G. Knepley         int eid;
1554c1cad2e7SMatthew G. Knepley 
15555552b385SBrandon         if (islite) {
15565552b385SBrandon           PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
15575552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
15585552b385SBrandon         } else {
15599566063dSJacob Faibussowitsch           PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
15605f80ce2aSJacob Faibussowitsch           eid = EG_indexBodyTopo(body, edge);
15615552b385SBrandon         }
1562c1cad2e7SMatthew G. Knepley 
15639566063dSJacob Faibussowitsch         PetscCall(PetscHMapIFind(edgeMap, edgeCntr + eid - 1, &EMiter, &EMfound));
1564c1cad2e7SMatthew G. Knepley         if (mtype == DEGENERATE) {
15659566063dSJacob Faibussowitsch           if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, -1));
15669371c9d4SSatish Balay         } else {
1567c1cad2e7SMatthew G. Knepley           ++Netemp;
15689566063dSJacob Faibussowitsch           if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, Netemp));
1569c1cad2e7SMatthew G. Knepley         }
1570c1cad2e7SMatthew G. Knepley       }
15715552b385SBrandon       if (islite) {
15725552b385SBrandon         EGlite_free(eobjs);
15735552b385SBrandon       } else {
1574c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
15755552b385SBrandon       }
1576c1cad2e7SMatthew G. Knepley 
1577c1cad2e7SMatthew G. Knepley       // Determine Number of Cells
15785552b385SBrandon       if (islite) {
15795552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15805552b385SBrandon       } else {
15819566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15825552b385SBrandon       }
15835552b385SBrandon 
1584c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1585c1cad2e7SMatthew G. Knepley         ego face     = fobjs[f];
1586c1cad2e7SMatthew G. Knepley         int edgeTemp = 0;
1587c1cad2e7SMatthew G. Knepley 
15885552b385SBrandon         if (islite) {
15895552b385SBrandon           PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
15905552b385SBrandon         } else {
15919566063dSJacob Faibussowitsch           PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
15925552b385SBrandon         }
15935552b385SBrandon 
1594c1cad2e7SMatthew G. Knepley         for (int e = 0; e < Ne; ++e) {
1595c1cad2e7SMatthew G. Knepley           ego edge = eobjs[e];
1596c1cad2e7SMatthew G. Knepley 
15975552b385SBrandon           if (islite) {
15985552b385SBrandon             PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
15995552b385SBrandon           } else {
16009566063dSJacob Faibussowitsch             PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16015552b385SBrandon           }
1602ad540459SPierre Jolivet           if (mtype != DEGENERATE) ++edgeTemp;
1603c1cad2e7SMatthew G. Knepley         }
1604c1cad2e7SMatthew G. Knepley         numCells += (2 * edgeTemp);
16055552b385SBrandon         if (islite) {
16065552b385SBrandon           EGlite_free(eobjs);
16075552b385SBrandon         } else {
1608c1cad2e7SMatthew G. Knepley           EG_free(eobjs);
1609c1cad2e7SMatthew G. Knepley         }
16105552b385SBrandon       }
16115552b385SBrandon       if (islite) {
16125552b385SBrandon         EGlite_free(fobjs);
16135552b385SBrandon       } else {
1614c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
16155552b385SBrandon       }
1616c1cad2e7SMatthew G. Knepley 
1617c1cad2e7SMatthew G. Knepley       numFaces += Nf;
1618c1cad2e7SMatthew G. Knepley       numEdges += Netemp;
1619c1cad2e7SMatthew G. Knepley       numVertices += Nv;
1620c1cad2e7SMatthew G. Knepley       edgeCntr += Ne;
1621c1cad2e7SMatthew G. Knepley     }
1622c1cad2e7SMatthew G. Knepley 
1623c1cad2e7SMatthew G. Knepley     // Set up basic DMPlex parameters
162435cb6cd3SPierre Jolivet     dim        = 2;                                 // Assumes 3D Models :: Need to handle 2D models in the future
162535cb6cd3SPierre Jolivet     cdim       = 3;                                 // Assumes 3D Models :: Need to update to handle 2D models in future
1626c1cad2e7SMatthew G. Knepley     numCorners = 3;                                 // Split Faces into triangles
1627c1cad2e7SMatthew G. Knepley     numPoints  = numVertices + numEdges + numFaces; // total number of coordinate points
1628c1cad2e7SMatthew G. Knepley 
16299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPoints * cdim, &coords, numCells * numCorners, &cells));
1630c1cad2e7SMatthew G. Knepley 
1631c1cad2e7SMatthew G. Knepley     // Get Vertex Coordinates and Set up Cells
1632c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
1633c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
1634c1cad2e7SMatthew G. Knepley       int           Nf, Ne, Nv;
1635c1cad2e7SMatthew G. Knepley       PetscInt      bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
1636c1cad2e7SMatthew G. Knepley       PetscHashIter BViter, BEiter, BEGiter, BFiter, EMiter;
1637c1cad2e7SMatthew G. Knepley       PetscBool     BVfound, BEfound, BEGfound, BFfound, EMfound;
1638c1cad2e7SMatthew G. Knepley 
1639c1cad2e7SMatthew G. Knepley       // Vertices on Current Body
16405552b385SBrandon       if (islite) {
16415552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
16425552b385SBrandon       } else {
16439566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
16445552b385SBrandon       }
1645c1cad2e7SMatthew G. Knepley 
16469566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
16475552b385SBrandon       PetscCheck(BVfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyVertexMap", b);
16489566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
1649c1cad2e7SMatthew G. Knepley 
1650c1cad2e7SMatthew G. Knepley       for (int v = 0; v < Nv; ++v) {
1651c1cad2e7SMatthew G. Knepley         ego    vertex = nobjs[v];
1652c1cad2e7SMatthew G. Knepley         double limits[4];
16532a8381b2SBarry Smith         int    id, unused;
1654c1cad2e7SMatthew G. Knepley 
16555552b385SBrandon         if (islite) {
16562a8381b2SBarry Smith           PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &unused, &mobjs, &senses));
16575552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
16585552b385SBrandon         } else {
16592a8381b2SBarry Smith           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &unused, &mobjs, &senses));
16605f80ce2aSJacob Faibussowitsch           id = EG_indexBodyTopo(body, vertex);
16615552b385SBrandon         }
1662c1cad2e7SMatthew G. Knepley 
1663c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 0] = limits[0];
1664c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 1] = limits[1];
1665c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 2] = limits[2];
1666c1cad2e7SMatthew G. Knepley       }
16675552b385SBrandon       if (islite) {
16685552b385SBrandon         EGlite_free(nobjs);
16695552b385SBrandon       } else {
1670c1cad2e7SMatthew G. Knepley         EG_free(nobjs);
16715552b385SBrandon       }
1672c1cad2e7SMatthew G. Knepley 
1673c1cad2e7SMatthew G. Knepley       // Edge Midpoint Vertices on Current Body
16745552b385SBrandon       if (islite) {
16755552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
16765552b385SBrandon       } else {
16779566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
16785552b385SBrandon       }
1679c1cad2e7SMatthew G. Knepley 
16809566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
16815552b385SBrandon       PetscCheck(BEfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyEdgeMap", b);
16829566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
1683c1cad2e7SMatthew G. Knepley 
16849566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
16855552b385SBrandon       PetscCheck(BEGfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyEdgeGlobalMap", b);
16869566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
1687c1cad2e7SMatthew G. Knepley 
1688c1cad2e7SMatthew G. Knepley       for (int e = 0; e < Ne; ++e) {
1689c1cad2e7SMatthew G. Knepley         ego    edge = eobjs[e];
1690c1cad2e7SMatthew G. Knepley         double range[2], avgt[1], cntrPnt[9];
1691c1cad2e7SMatthew G. Knepley         int    eid, eOffset;
1692c1cad2e7SMatthew G. Knepley         int    periodic;
1693c1cad2e7SMatthew G. Knepley 
16945552b385SBrandon         if (islite) {
16955552b385SBrandon           PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16965552b385SBrandon         } else {
16979566063dSJacob Faibussowitsch           PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16985552b385SBrandon         }
1699ad540459SPierre Jolivet         if (mtype == DEGENERATE) continue;
1700c1cad2e7SMatthew G. Knepley 
17015552b385SBrandon         if (islite) {
17025552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
17035552b385SBrandon         } else {
17045f80ce2aSJacob Faibussowitsch           eid = EG_indexBodyTopo(body, edge);
17055552b385SBrandon         }
1706c1cad2e7SMatthew G. Knepley         // get relative offset from globalEdgeID Vector
17079566063dSJacob Faibussowitsch         PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
17085552b385SBrandon         PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " not found in edgeMap", bodyEdgeGlobalIndexStart + eid - 1);
17099566063dSJacob Faibussowitsch         PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1710c1cad2e7SMatthew G. Knepley 
17115552b385SBrandon         if (islite) {
17125552b385SBrandon           PetscCall(EGlite_getRange(edge, range, &periodic));
17135552b385SBrandon         } else {
17149566063dSJacob Faibussowitsch           PetscCall(EG_getRange(edge, range, &periodic));
17155552b385SBrandon         }
1716c1cad2e7SMatthew G. Knepley         avgt[0] = (range[0] + range[1]) / 2.;
1717c1cad2e7SMatthew G. Knepley 
17185552b385SBrandon         if (islite) {
17195552b385SBrandon           PetscCall(EGlite_evaluate(edge, avgt, cntrPnt));
17205552b385SBrandon         } else {
17219566063dSJacob Faibussowitsch           PetscCall(EG_evaluate(edge, avgt, cntrPnt));
17225552b385SBrandon         }
1723c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 0] = cntrPnt[0];
1724c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 1] = cntrPnt[1];
1725c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 2] = cntrPnt[2];
1726c1cad2e7SMatthew G. Knepley       }
17275552b385SBrandon       if (islite) {
17285552b385SBrandon         EGlite_free(eobjs);
17295552b385SBrandon       } else {
1730c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
17315552b385SBrandon       }
1732c1cad2e7SMatthew G. Knepley       // Face Midpoint Vertices on Current Body
17335552b385SBrandon       if (islite) {
17345552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17355552b385SBrandon       } else {
17369566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17375552b385SBrandon       }
17389566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
173928b400f6SJacob Faibussowitsch       PetscCheck(BFfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
17409566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
1741c1cad2e7SMatthew G. Knepley 
1742c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1743c1cad2e7SMatthew G. Knepley         ego    face = fobjs[f];
1744c1cad2e7SMatthew G. Knepley         double range[4], avgUV[2], cntrPnt[18];
1745c1cad2e7SMatthew G. Knepley         int    peri, id;
1746c1cad2e7SMatthew G. Knepley 
17475552b385SBrandon         if (islite) {
17485552b385SBrandon           id = EGlite_indexBodyTopo(body, face);
17495552b385SBrandon           PetscCall(EGlite_getRange(face, range, &peri));
17505552b385SBrandon         } else {
1751c1cad2e7SMatthew G. Knepley           id = EG_indexBodyTopo(body, face);
17529566063dSJacob Faibussowitsch           PetscCall(EG_getRange(face, range, &peri));
17535552b385SBrandon         }
1754c1cad2e7SMatthew G. Knepley 
1755c1cad2e7SMatthew G. Knepley         avgUV[0] = (range[0] + range[1]) / 2.;
1756c1cad2e7SMatthew G. Knepley         avgUV[1] = (range[2] + range[3]) / 2.;
17575552b385SBrandon 
17585552b385SBrandon         if (islite) {
17595552b385SBrandon           PetscCall(EGlite_evaluate(face, avgUV, cntrPnt));
17605552b385SBrandon         } else {
17619566063dSJacob Faibussowitsch           PetscCall(EG_evaluate(face, avgUV, cntrPnt));
17625552b385SBrandon         }
1763c1cad2e7SMatthew G. Knepley 
1764c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 0] = cntrPnt[0];
1765c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 1] = cntrPnt[1];
1766c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 2] = cntrPnt[2];
1767c1cad2e7SMatthew G. Knepley       }
17685552b385SBrandon       if (islite) {
17695552b385SBrandon         EGlite_free(fobjs);
17705552b385SBrandon       } else {
1771c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
17725552b385SBrandon       }
1773c1cad2e7SMatthew G. Knepley 
1774c1cad2e7SMatthew G. Knepley       // Define Cells :: Note - This could be incorporated in the Face Midpoint Vertices Loop but was kept separate for clarity
17755552b385SBrandon       if (islite) {
17765552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17775552b385SBrandon       } else {
17789566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17795552b385SBrandon       }
1780c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1781c1cad2e7SMatthew G. Knepley         ego face = fobjs[f];
1782c1cad2e7SMatthew G. Knepley         int fID, midFaceID, midPntID, startID, endID, Nl;
1783c1cad2e7SMatthew G. Knepley 
17845552b385SBrandon         if (islite) {
17855552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
17865552b385SBrandon         } else {
17875f80ce2aSJacob Faibussowitsch           fID = EG_indexBodyTopo(body, face);
17885552b385SBrandon         }
17895552b385SBrandon 
1790c1cad2e7SMatthew G. Knepley         midFaceID = numVertices + numEdges + bodyFaceIndexStart + fID - 1;
1791c1cad2e7SMatthew G. Knepley         // Must Traverse Loop to ensure we have all necessary information like the sense (+/- 1) of the edges.
1792c1cad2e7SMatthew G. Knepley         // TODO :: Only handles single loop faces (No holes). The choices for handling multiloop faces are:
17935552b385SBrandon         //            1) Use the DMPlexCreateGeomFromFile() with the -dm_plex_geom_with_tess = 1 option.
1794c1cad2e7SMatthew G. Knepley         //               This will use a default EGADS tessellation as an initial surface mesh.
1795d5b43468SJose E. Roman         //            2) Create the initial surface mesh via a 2D mesher :: Currently not available (?future?)
1796c1cad2e7SMatthew G. Knepley         //               May I suggest the XXXX as a starting point?
1797c1cad2e7SMatthew G. Knepley 
17985552b385SBrandon         if (islite) {
17995552b385SBrandon           PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
18005552b385SBrandon         } else {
18019566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
18025552b385SBrandon         }
1803c1cad2e7SMatthew G. Knepley 
18045552b385SBrandon         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);
1805c1cad2e7SMatthew G. Knepley         for (int l = 0; l < Nl; ++l) {
1806c1cad2e7SMatthew G. Knepley           ego loop = lobjs[l];
1807c1cad2e7SMatthew G. Knepley 
18085552b385SBrandon           if (islite) {
18095552b385SBrandon             PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
18105552b385SBrandon           } else {
18119566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
18125552b385SBrandon           }
18135552b385SBrandon 
1814c1cad2e7SMatthew G. Knepley           for (int e = 0; e < Ne; ++e) {
1815c1cad2e7SMatthew G. Knepley             ego edge = eobjs[e];
1816c1cad2e7SMatthew G. Knepley             int eid, eOffset;
1817c1cad2e7SMatthew G. Knepley 
18185552b385SBrandon             if (islite) {
18195552b385SBrandon               PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
18205552b385SBrandon               eid = EGlite_indexBodyTopo(body, edge);
18215552b385SBrandon             } else {
18229566063dSJacob Faibussowitsch               PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1823c1cad2e7SMatthew G. Knepley               eid = EG_indexBodyTopo(body, edge);
18245552b385SBrandon             }
1825ad540459SPierre Jolivet             if (mtype == DEGENERATE) continue;
1826c1cad2e7SMatthew G. Knepley 
1827c1cad2e7SMatthew G. Knepley             // get relative offset from globalEdgeID Vector
18289566063dSJacob Faibussowitsch             PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
18295552b385SBrandon             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);
18309566063dSJacob Faibussowitsch             PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1831c1cad2e7SMatthew G. Knepley 
1832c1cad2e7SMatthew G. Knepley             midPntID = numVertices + bodyEdgeIndexStart + eOffset - 1;
1833c1cad2e7SMatthew G. Knepley 
18345552b385SBrandon             if (islite) {
18355552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
18365552b385SBrandon             } else {
18379566063dSJacob Faibussowitsch               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
18385552b385SBrandon             }
1839c1cad2e7SMatthew G. Knepley 
18409371c9d4SSatish Balay             if (eSenses[e] > 0) {
18415552b385SBrandon               if (islite) {
18425552b385SBrandon                 startID = EGlite_indexBodyTopo(body, nobjs[0]);
18435552b385SBrandon                 endID   = EGlite_indexBodyTopo(body, nobjs[1]);
18445552b385SBrandon               } else {
18459371c9d4SSatish Balay                 startID = EG_indexBodyTopo(body, nobjs[0]);
18469371c9d4SSatish Balay                 endID   = EG_indexBodyTopo(body, nobjs[1]);
18475552b385SBrandon               }
18485552b385SBrandon             } else {
18495552b385SBrandon               if (islite) {
18505552b385SBrandon                 startID = EGlite_indexBodyTopo(body, nobjs[1]);
18515552b385SBrandon                 endID   = EGlite_indexBodyTopo(body, nobjs[0]);
18529371c9d4SSatish Balay               } else {
18539371c9d4SSatish Balay                 startID = EG_indexBodyTopo(body, nobjs[1]);
18549371c9d4SSatish Balay                 endID   = EG_indexBodyTopo(body, nobjs[0]);
18559371c9d4SSatish Balay               }
18565552b385SBrandon             }
1857c1cad2e7SMatthew G. Knepley 
1858c1cad2e7SMatthew G. Knepley             // Define 2 Cells per Edge with correct orientation
1859c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 0] = midFaceID;
1860c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 1] = bodyVertexIndexStart + startID - 1;
1861c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 2] = midPntID;
1862c1cad2e7SMatthew G. Knepley 
1863c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 3] = midFaceID;
1864c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 4] = midPntID;
1865c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 5] = bodyVertexIndexStart + endID - 1;
1866c1cad2e7SMatthew G. Knepley 
1867c1cad2e7SMatthew G. Knepley             cellCntr = cellCntr + 2;
1868c1cad2e7SMatthew G. Knepley           }
1869c1cad2e7SMatthew G. Knepley         }
1870c1cad2e7SMatthew G. Knepley       }
18715552b385SBrandon       if (islite) {
18725552b385SBrandon         EGlite_free(fobjs);
18735552b385SBrandon       } else {
1874c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1875c1cad2e7SMatthew G. Knepley       }
1876c1cad2e7SMatthew G. Knepley     }
18775552b385SBrandon   }
1878c1cad2e7SMatthew G. Knepley 
1879c1cad2e7SMatthew G. Knepley   // Generate DMPlex
18809566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
18819566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coords, cells));
188263a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %" PetscInt_FMT " \n", numCells));
188363a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, " Total Number of Unique Vertices = %" PetscInt_FMT " \n", numVertices));
1884c1cad2e7SMatthew G. Knepley 
1885c1cad2e7SMatthew G. Knepley   // Embed EGADS model in DM
1886c1cad2e7SMatthew G. Knepley   {
1887c1cad2e7SMatthew G. Knepley     PetscContainer modelObj, contextObj;
1888c1cad2e7SMatthew G. Knepley 
18899566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
18909566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
18915552b385SBrandon     if (islite) {
18925552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSliteDestroy_Private));
18935552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Model", (PetscObject)modelObj));
18945552b385SBrandon     } else {
18955552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSDestroy_Private));
18969566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
18975552b385SBrandon     }
18989566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
1899c1cad2e7SMatthew G. Knepley 
19009566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
19019566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
19025552b385SBrandon 
19035552b385SBrandon     if (islite) {
19045552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSliteClose_Private));
19055552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Context", (PetscObject)contextObj));
19065552b385SBrandon     } else {
19075552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSClose_Private));
19089566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
19095552b385SBrandon     }
19109566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
1911c1cad2e7SMatthew G. Knepley   }
1912c1cad2e7SMatthew G. Knepley   // Label points
1913c1cad2e7SMatthew G. Knepley   PetscInt nStart, nEnd;
1914c1cad2e7SMatthew G. Knepley 
19159566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
19169566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
19179566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
19189566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
19199566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
19209566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
19219566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
19229566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
1923c1cad2e7SMatthew G. Knepley 
19249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
1925c1cad2e7SMatthew G. Knepley 
1926c1cad2e7SMatthew G. Knepley   cellCntr = 0;
1927c1cad2e7SMatthew G. Knepley   for (b = 0; b < nbodies; ++b) {
1928c1cad2e7SMatthew G. Knepley     ego           body = bodies[b];
1929c1cad2e7SMatthew G. Knepley     int           Nv, Ne, Nf;
1930c1cad2e7SMatthew G. Knepley     PetscInt      bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
1931c1cad2e7SMatthew G. Knepley     PetscHashIter BViter, BEiter, BEGiter, BFiter, EMiter;
1932c1cad2e7SMatthew G. Knepley     PetscBool     BVfound, BEfound, BEGfound, BFfound, EMfound;
1933c1cad2e7SMatthew G. Knepley 
19349566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
193528b400f6SJacob Faibussowitsch     PetscCheck(BVfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyVertexMap", b);
19369566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
1937c1cad2e7SMatthew G. Knepley 
19389566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
193928b400f6SJacob Faibussowitsch     PetscCheck(BEfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeMap", b);
19409566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
1941c1cad2e7SMatthew G. Knepley 
19429566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
194328b400f6SJacob Faibussowitsch     PetscCheck(BFfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
19449566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
1945c1cad2e7SMatthew G. Knepley 
19469566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
194728b400f6SJacob Faibussowitsch     PetscCheck(BEGfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeGlobalMap", b);
19489566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
1949c1cad2e7SMatthew G. Knepley 
19505552b385SBrandon     if (islite) {
19515552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
19525552b385SBrandon     } else {
19539566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
19545552b385SBrandon     }
19555552b385SBrandon 
1956c1cad2e7SMatthew G. Knepley     for (int f = 0; f < Nf; ++f) {
1957c1cad2e7SMatthew G. Knepley       ego face = fobjs[f];
1958c1cad2e7SMatthew G. Knepley       int fID, Nl;
1959c1cad2e7SMatthew G. Knepley 
19605552b385SBrandon       if (islite) {
19615552b385SBrandon         fID = EGlite_indexBodyTopo(body, face);
19625552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
19635552b385SBrandon       } else {
19645f80ce2aSJacob Faibussowitsch         fID = EG_indexBodyTopo(body, face);
19659566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
19665552b385SBrandon       }
19675552b385SBrandon 
1968c1cad2e7SMatthew G. Knepley       for (int l = 0; l < Nl; ++l) {
1969c1cad2e7SMatthew G. Knepley         ego loop = lobjs[l];
1970c1cad2e7SMatthew G. Knepley         int lid;
1971c1cad2e7SMatthew G. Knepley 
19725552b385SBrandon         if (islite) {
19735552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
19745552b385SBrandon         } else {
19755f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
19765552b385SBrandon         }
1977c1cad2e7SMatthew G. Knepley 
19785552b385SBrandon         PetscCheck(Nl == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %" PetscInt_FMT " has %" PetscInt_FMT " > 1 faces, which is not supported", lid, Nf);
19795552b385SBrandon 
19805552b385SBrandon         if (islite) {
19815552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
19825552b385SBrandon         } else {
19839566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
19845552b385SBrandon         }
19855552b385SBrandon 
1986c1cad2e7SMatthew G. Knepley         for (int e = 0; e < Ne; ++e) {
1987c1cad2e7SMatthew G. Knepley           ego edge = eobjs[e];
1988c1cad2e7SMatthew G. Knepley           int eid, eOffset;
1989c1cad2e7SMatthew G. Knepley 
1990c1cad2e7SMatthew G. Knepley           // Skip DEGENERATE Edges
19915552b385SBrandon           if (islite) {
19925552b385SBrandon             PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
19935552b385SBrandon           } else {
19949566063dSJacob Faibussowitsch             PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
19955552b385SBrandon           }
19965552b385SBrandon 
1997ac530a7eSPierre Jolivet           if (mtype == DEGENERATE) continue;
19985552b385SBrandon 
19995552b385SBrandon           if (islite) {
20005552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
20015552b385SBrandon           } else {
20025f80ce2aSJacob Faibussowitsch             eid = EG_indexBodyTopo(body, edge);
20035552b385SBrandon           }
2004c1cad2e7SMatthew G. Knepley 
2005c1cad2e7SMatthew G. Knepley           // get relative offset from globalEdgeID Vector
20069566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
20075552b385SBrandon           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);
20089566063dSJacob Faibussowitsch           PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
2009c1cad2e7SMatthew G. Knepley 
20105552b385SBrandon           if (islite) {
20115552b385SBrandon             PetscCall(EGlite_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
20125552b385SBrandon           } else {
20139566063dSJacob Faibussowitsch             PetscCall(EG_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
20145552b385SBrandon           }
20155552b385SBrandon 
2016c1cad2e7SMatthew G. Knepley           for (int v = 0; v < Nv; ++v) {
2017c1cad2e7SMatthew G. Knepley             ego vertex = nobjs[v];
2018c1cad2e7SMatthew G. Knepley             int vID;
2019c1cad2e7SMatthew G. Knepley 
20205552b385SBrandon             if (islite) {
20215552b385SBrandon               vID = EGlite_indexBodyTopo(body, vertex);
20225552b385SBrandon             } else {
20235f80ce2aSJacob Faibussowitsch               vID = EG_indexBodyTopo(body, vertex);
20245552b385SBrandon             }
20255552b385SBrandon 
20269566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, nStart + bodyVertexIndexStart + vID - 1, b));
20279566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(vertexLabel, nStart + bodyVertexIndexStart + vID - 1, vID));
2028c1cad2e7SMatthew G. Knepley           }
20295552b385SBrandon           if (islite) {
20305552b385SBrandon             EGlite_free(nobjs);
20315552b385SBrandon           } else {
2032c1cad2e7SMatthew G. Knepley             EG_free(nobjs);
20335552b385SBrandon           }
2034c1cad2e7SMatthew G. Knepley 
20359566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, b));
20369566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(edgeLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, eid));
2037c1cad2e7SMatthew G. Knepley 
2038c1cad2e7SMatthew G. Knepley           // Define Cell faces
2039c1cad2e7SMatthew G. Knepley           for (int jj = 0; jj < 2; ++jj) {
20409566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cellCntr, b));
20419566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cellCntr, fID));
20429566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cellCntr, &cone));
2043c1cad2e7SMatthew G. Knepley 
20449566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[0], b));
20459566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cone[0], fID));
2046c1cad2e7SMatthew G. Knepley 
20479566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[1], b));
20489566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(edgeLabel, cone[1], eid));
2049c1cad2e7SMatthew G. Knepley 
20509566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[2], b));
20519566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cone[2], fID));
2052c1cad2e7SMatthew G. Knepley 
2053c1cad2e7SMatthew G. Knepley             cellCntr = cellCntr + 1;
2054c1cad2e7SMatthew G. Knepley           }
2055c1cad2e7SMatthew G. Knepley         }
2056c1cad2e7SMatthew G. Knepley       }
20575552b385SBrandon       if (islite) {
20585552b385SBrandon         EGlite_free(lobjs);
20595552b385SBrandon       } else {
2060c1cad2e7SMatthew G. Knepley         EG_free(lobjs);
20615552b385SBrandon       }
2062c1cad2e7SMatthew G. Knepley 
20639566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, b));
20649566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(faceLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, fID));
2065c1cad2e7SMatthew G. Knepley     }
20665552b385SBrandon     if (islite) {
20675552b385SBrandon       EGlite_free(fobjs);
20685552b385SBrandon     } else {
2069c1cad2e7SMatthew G. Knepley       EG_free(fobjs);
2070c1cad2e7SMatthew G. Knepley     }
20715552b385SBrandon   }
2072c1cad2e7SMatthew G. Knepley 
20739566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&edgeMap));
20749566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyIndexMap));
20759566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyVertexMap));
20769566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyEdgeMap));
20779566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyEdgeGlobalMap));
20789566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyFaceMap));
2079c1cad2e7SMatthew G. Knepley 
2080c1cad2e7SMatthew G. Knepley   *newdm = dm;
20813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2082c1cad2e7SMatthew G. Knepley }
2083c1cad2e7SMatthew G. Knepley 
DMPlexCreateGeom_Tess_Internal(MPI_Comm comm,ego context,ego model,DM * newdm,PetscBool islite)20845552b385SBrandon PetscErrorCode DMPlexCreateGeom_Tess_Internal(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
2085d71ae5a4SJacob Faibussowitsch {
20865552b385SBrandon   /* EGADSlite variables */
2087c1cad2e7SMatthew G. Knepley   ego    geom, *bodies, *fobjs;
2088c1cad2e7SMatthew G. Knepley   int    b, oclass, mtype, nbodies, *senses;
2089c1cad2e7SMatthew G. Knepley   int    totalNumTris = 0, totalNumPoints = 0;
2090c1cad2e7SMatthew G. Knepley   double boundBox[6] = {0., 0., 0., 0., 0., 0.}, tessSize;
2091c1cad2e7SMatthew G. Knepley   /* PETSc variables */
2092c1cad2e7SMatthew G. Knepley   DM              dm;
20935552b385SBrandon   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
2094c1cad2e7SMatthew G. Knepley   PetscHMapI      pointIndexStartMap = NULL, triIndexStartMap = NULL, pTypeLabelMap = NULL, pIndexLabelMap = NULL;
2095c1cad2e7SMatthew G. Knepley   PetscHMapI      pBodyIndexLabelMap = NULL, triFaceIDLabelMap = NULL, triBodyIDLabelMap = NULL;
2096c1cad2e7SMatthew G. Knepley   PetscInt        dim = -1, cdim = -1, numCorners = 0, counter = 0;
2097c1cad2e7SMatthew G. Knepley   PetscInt       *cells  = NULL;
2098c1cad2e7SMatthew G. Knepley   const PetscInt *cone   = NULL;
2099c1cad2e7SMatthew G. Knepley   PetscReal      *coords = NULL;
2100c1cad2e7SMatthew G. Knepley   PetscMPIInt     rank;
2101c1cad2e7SMatthew G. Knepley 
2102c1cad2e7SMatthew G. Knepley   PetscFunctionBeginUser;
21039566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2104c5853193SPierre Jolivet   if (rank == 0) {
2105f0b74427SPierre Jolivet     // Generate PETSc DMPlex from EGADSlite created Tessellation of geometry
2106c1cad2e7SMatthew G. Knepley 
2107d5b43468SJose E. Roman     // Calculate cell and vertex sizes
21085552b385SBrandon     if (islite) {
21095552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
21105552b385SBrandon     } else {
21119566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
21125552b385SBrandon     }
2113c1cad2e7SMatthew G. Knepley 
21149566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pointIndexStartMap));
21159566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triIndexStartMap));
21169566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pTypeLabelMap));
21179566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pIndexLabelMap));
21189566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pBodyIndexLabelMap));
21199566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triFaceIDLabelMap));
21209566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triBodyIDLabelMap));
2121c1cad2e7SMatthew G. Knepley 
2122c1cad2e7SMatthew G. Knepley     /* Create Tessellation of Bodies */
21235552b385SBrandon     ego *tessArray;
2124c1cad2e7SMatthew G. Knepley 
21255552b385SBrandon     PetscCall(PetscMalloc1(nbodies, &tessArray));
2126c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
2127c1cad2e7SMatthew G. Knepley       ego           body      = bodies[b];
2128c1cad2e7SMatthew G. Knepley       double        params[3] = {0.0, 0.0, 0.0}; // Parameters for Tessellation
2129c1cad2e7SMatthew G. Knepley       int           Nf, bodyNumPoints = 0, bodyNumTris = 0;
2130c1cad2e7SMatthew G. Knepley       PetscHashIter PISiter, TISiter;
2131c1cad2e7SMatthew G. Knepley       PetscBool     PISfound, TISfound;
2132c1cad2e7SMatthew G. Knepley 
2133c1cad2e7SMatthew G. Knepley       /* Store Start Index for each Body's Point and Tris */
21349566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
21359566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(triIndexStartMap, b, &TISiter, &TISfound));
2136c1cad2e7SMatthew G. Knepley 
21379566063dSJacob Faibussowitsch       if (!PISfound) PetscCall(PetscHMapISet(pointIndexStartMap, b, totalNumPoints));
21389566063dSJacob Faibussowitsch       if (!TISfound) PetscCall(PetscHMapISet(triIndexStartMap, b, totalNumTris));
2139c1cad2e7SMatthew G. Knepley 
2140c1cad2e7SMatthew G. Knepley       /* Calculate Tessellation parameters based on Bounding Box */
2141c1cad2e7SMatthew G. Knepley       /* Get Bounding Box Dimensions of the BODY */
21425552b385SBrandon       if (islite) {
21435552b385SBrandon         PetscCall(EGlite_getBoundingBox(body, boundBox));
21445552b385SBrandon       } else {
21459566063dSJacob Faibussowitsch         PetscCall(EG_getBoundingBox(body, boundBox));
21465552b385SBrandon       }
21475552b385SBrandon 
2148c1cad2e7SMatthew G. Knepley       tessSize = boundBox[3] - boundBox[0];
2149c1cad2e7SMatthew G. Knepley       if (tessSize < boundBox[4] - boundBox[1]) tessSize = boundBox[4] - boundBox[1];
2150c1cad2e7SMatthew G. Knepley       if (tessSize < boundBox[5] - boundBox[2]) tessSize = boundBox[5] - boundBox[2];
2151c1cad2e7SMatthew G. Knepley 
2152c1cad2e7SMatthew G. Knepley       // TODO :: May want to give users tessellation parameter options //
2153c1cad2e7SMatthew G. Knepley       params[0] = 0.0250 * tessSize;
2154c1cad2e7SMatthew G. Knepley       params[1] = 0.0075 * tessSize;
2155c1cad2e7SMatthew G. Knepley       params[2] = 15.0;
2156c1cad2e7SMatthew G. Knepley 
21575552b385SBrandon       if (islite) {
21585552b385SBrandon         PetscCall(EGlite_makeTessBody(body, params, &tessArray[b]));
21595552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
21605552b385SBrandon       } else {
21619566063dSJacob Faibussowitsch         PetscCall(EG_makeTessBody(body, params, &tessArray[b]));
21629566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
21635552b385SBrandon       }
2164c1cad2e7SMatthew G. Knepley 
2165c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
2166c1cad2e7SMatthew G. Knepley         ego           face = fobjs[f];
2167c1cad2e7SMatthew G. Knepley         int           len, fID, ntris;
2168c1cad2e7SMatthew G. Knepley         const int    *ptype, *pindex, *ptris, *ptric;
2169c1cad2e7SMatthew G. Knepley         const double *pxyz, *puv;
2170c1cad2e7SMatthew G. Knepley 
2171c1cad2e7SMatthew G. Knepley         // Get Face ID //
21725552b385SBrandon         if (islite) {
21735552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
21745552b385SBrandon         } else {
2175c1cad2e7SMatthew G. Knepley           fID = EG_indexBodyTopo(body, face);
21765552b385SBrandon         }
2177c1cad2e7SMatthew G. Knepley 
2178c1cad2e7SMatthew G. Knepley         // Checkout the Surface Tessellation //
21795552b385SBrandon         if (islite) {
21805552b385SBrandon           PetscCall(EGlite_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
21815552b385SBrandon         } else {
21829566063dSJacob Faibussowitsch           PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
21835552b385SBrandon         }
2184c1cad2e7SMatthew G. Knepley 
2185c1cad2e7SMatthew G. Knepley         // Determine total number of triangle cells in the tessellation //
2186c1cad2e7SMatthew G. Knepley         bodyNumTris += (int)ntris;
2187c1cad2e7SMatthew G. Knepley 
2188c1cad2e7SMatthew G. Knepley         // Check out the point index and coordinate //
2189c1cad2e7SMatthew G. Knepley         for (int p = 0; p < len; ++p) {
2190c1cad2e7SMatthew G. Knepley           int global;
2191c1cad2e7SMatthew G. Knepley 
21925552b385SBrandon           if (islite) {
21935552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, p + 1, &global));
21945552b385SBrandon           } else {
21959566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, p + 1, &global));
21965552b385SBrandon           }
2197c1cad2e7SMatthew G. Knepley 
2198c1cad2e7SMatthew G. Knepley           // Determine the total number of points in the tessellation //
2199c1cad2e7SMatthew G. Knepley           bodyNumPoints = PetscMax(bodyNumPoints, global);
2200c1cad2e7SMatthew G. Knepley         }
2201c1cad2e7SMatthew G. Knepley       }
22025552b385SBrandon       if (islite) {
22035552b385SBrandon         EGlite_free(fobjs);
22045552b385SBrandon       } else {
2205c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
22065552b385SBrandon       }
2207c1cad2e7SMatthew G. Knepley 
2208c1cad2e7SMatthew G. Knepley       totalNumPoints += bodyNumPoints;
2209c1cad2e7SMatthew G. Knepley       totalNumTris += bodyNumTris;
2210c1cad2e7SMatthew G. Knepley     }
2211c1cad2e7SMatthew G. Knepley 
2212c1cad2e7SMatthew G. Knepley     dim        = 2;
2213c1cad2e7SMatthew G. Knepley     cdim       = 3;
2214c1cad2e7SMatthew G. Knepley     numCorners = 3;
2215c1cad2e7SMatthew G. Knepley 
2216c1cad2e7SMatthew G. Knepley     /* NEED TO DEFINE MATRICES/VECTORS TO STORE GEOM REFERENCE DATA   */
2217c1cad2e7SMatthew G. Knepley     /* Fill in below and use to define DMLabels after DMPlex creation */
22189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(totalNumPoints * cdim, &coords, totalNumTris * numCorners, &cells));
2219c1cad2e7SMatthew G. Knepley 
2220c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
2221c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
2222c1cad2e7SMatthew G. Knepley       int           Nf;
2223c1cad2e7SMatthew G. Knepley       PetscInt      pointIndexStart;
2224c1cad2e7SMatthew G. Knepley       PetscHashIter PISiter;
2225c1cad2e7SMatthew G. Knepley       PetscBool     PISfound;
2226c1cad2e7SMatthew G. Knepley 
22279566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
22285552b385SBrandon       PetscCheck(PISfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in pointIndexStartMap", b);
22299566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(pointIndexStartMap, b, &pointIndexStart));
2230c1cad2e7SMatthew G. Knepley 
22315552b385SBrandon       if (islite) {
22325552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
22335552b385SBrandon       } else {
22349566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
22355552b385SBrandon       }
2236c1cad2e7SMatthew G. Knepley 
2237c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
2238c1cad2e7SMatthew G. Knepley         /* Get Face Object */
2239c1cad2e7SMatthew G. Knepley         ego           face = fobjs[f];
2240c1cad2e7SMatthew G. Knepley         int           len, fID, ntris;
2241c1cad2e7SMatthew G. Knepley         const int    *ptype, *pindex, *ptris, *ptric;
2242c1cad2e7SMatthew G. Knepley         const double *pxyz, *puv;
2243c1cad2e7SMatthew G. Knepley 
2244c1cad2e7SMatthew G. Knepley         /* Get Face ID */
22455552b385SBrandon         if (islite) {
22465552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
22475552b385SBrandon         } else {
2248c1cad2e7SMatthew G. Knepley           fID = EG_indexBodyTopo(body, face);
22495552b385SBrandon         }
2250c1cad2e7SMatthew G. Knepley 
2251c1cad2e7SMatthew G. Knepley         /* Checkout the Surface Tessellation */
22525552b385SBrandon         if (islite) {
22535552b385SBrandon           PetscCall(EGlite_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
22545552b385SBrandon         } else {
22559566063dSJacob Faibussowitsch           PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
22565552b385SBrandon         }
2257c1cad2e7SMatthew G. Knepley 
2258c1cad2e7SMatthew G. Knepley         /* Check out the point index and coordinate */
2259c1cad2e7SMatthew G. Knepley         for (int p = 0; p < len; ++p) {
2260c1cad2e7SMatthew G. Knepley           int           global;
2261c1cad2e7SMatthew G. Knepley           PetscHashIter PTLiter, PILiter, PBLiter;
2262c1cad2e7SMatthew G. Knepley           PetscBool     PTLfound, PILfound, PBLfound;
2263c1cad2e7SMatthew G. Knepley 
22645552b385SBrandon           if (islite) {
22655552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, p + 1, &global));
22665552b385SBrandon           } else {
22679566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, p + 1, &global));
22685552b385SBrandon           }
2269c1cad2e7SMatthew G. Knepley 
2270c1cad2e7SMatthew G. Knepley           /* Set the coordinates array for DAG */
2271c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 0] = pxyz[(p * 3) + 0];
2272c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 1] = pxyz[(p * 3) + 1];
2273c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 2] = pxyz[(p * 3) + 2];
2274c1cad2e7SMatthew G. Knepley 
2275c1cad2e7SMatthew G. Knepley           /* Store Geometry Label Information for DMLabel assignment later */
22769566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pTypeLabelMap, global - 1 + pointIndexStart, &PTLiter, &PTLfound));
22779566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pIndexLabelMap, global - 1 + pointIndexStart, &PILiter, &PILfound));
22789566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pBodyIndexLabelMap, global - 1 + pointIndexStart, &PBLiter, &PBLfound));
2279c1cad2e7SMatthew G. Knepley 
22809566063dSJacob Faibussowitsch           if (!PTLfound) PetscCall(PetscHMapISet(pTypeLabelMap, global - 1 + pointIndexStart, ptype[p]));
22819566063dSJacob Faibussowitsch           if (!PILfound) PetscCall(PetscHMapISet(pIndexLabelMap, global - 1 + pointIndexStart, pindex[p]));
22829566063dSJacob Faibussowitsch           if (!PBLfound) PetscCall(PetscHMapISet(pBodyIndexLabelMap, global - 1 + pointIndexStart, b));
2283c1cad2e7SMatthew G. Knepley 
22849566063dSJacob Faibussowitsch           if (ptype[p] < 0) PetscCall(PetscHMapISet(pIndexLabelMap, global - 1 + pointIndexStart, fID));
2285c1cad2e7SMatthew G. Knepley         }
2286c1cad2e7SMatthew G. Knepley 
2287c1cad2e7SMatthew G. Knepley         for (int t = 0; t < (int)ntris; ++t) {
2288c1cad2e7SMatthew G. Knepley           int           global, globalA, globalB;
2289c1cad2e7SMatthew G. Knepley           PetscHashIter TFLiter, TBLiter;
2290c1cad2e7SMatthew G. Knepley           PetscBool     TFLfound, TBLfound;
2291c1cad2e7SMatthew G. Knepley 
22925552b385SBrandon           if (islite) {
22935552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 0], &global));
22945552b385SBrandon           } else {
22959566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 0], &global));
22965552b385SBrandon           }
2297c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 0] = global - 1 + pointIndexStart;
2298c1cad2e7SMatthew G. Knepley 
22995552b385SBrandon           if (islite) {
23005552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 1], &globalA));
23015552b385SBrandon           } else {
23029566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 1], &globalA));
23035552b385SBrandon           }
2304c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 1] = globalA - 1 + pointIndexStart;
2305c1cad2e7SMatthew G. Knepley 
23065552b385SBrandon           if (islite) {
23075552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 2], &globalB));
23085552b385SBrandon           } else {
23099566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 2], &globalB));
23105552b385SBrandon           }
2311c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 2] = globalB - 1 + pointIndexStart;
2312c1cad2e7SMatthew G. Knepley 
23139566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(triFaceIDLabelMap, counter, &TFLiter, &TFLfound));
23149566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(triBodyIDLabelMap, counter, &TBLiter, &TBLfound));
2315c1cad2e7SMatthew G. Knepley 
23169566063dSJacob Faibussowitsch           if (!TFLfound) PetscCall(PetscHMapISet(triFaceIDLabelMap, counter, fID));
23179566063dSJacob Faibussowitsch           if (!TBLfound) PetscCall(PetscHMapISet(triBodyIDLabelMap, counter, b));
2318c1cad2e7SMatthew G. Knepley 
2319c1cad2e7SMatthew G. Knepley           counter += 1;
2320c1cad2e7SMatthew G. Knepley         }
2321c1cad2e7SMatthew G. Knepley       }
23225552b385SBrandon       if (islite) {
23235552b385SBrandon         EGlite_free(fobjs);
23245552b385SBrandon       } else {
2325c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
2326c1cad2e7SMatthew G. Knepley       }
2327c1cad2e7SMatthew G. Knepley     }
23285552b385SBrandon     PetscCall(PetscFree(tessArray));
23295552b385SBrandon   }
2330c1cad2e7SMatthew G. Knepley 
2331c1cad2e7SMatthew G. Knepley   //Build DMPlex
23329566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, totalNumTris, totalNumPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
23339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coords, cells));
2334c1cad2e7SMatthew G. Knepley 
2335c1cad2e7SMatthew G. Knepley   // Embed EGADS model in DM
2336c1cad2e7SMatthew G. Knepley   {
2337c1cad2e7SMatthew G. Knepley     PetscContainer modelObj, contextObj;
2338c1cad2e7SMatthew G. Knepley 
23399566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
23409566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
23415552b385SBrandon     if (islite) {
23422a8381b2SBarry Smith       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSliteDestroy_Private));
23435552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Model", (PetscObject)modelObj));
23445552b385SBrandon     } else {
23452a8381b2SBarry Smith       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSDestroy_Private));
23469566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
23475552b385SBrandon     }
23489566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
2349c1cad2e7SMatthew G. Knepley 
23509566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
23519566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
23525552b385SBrandon 
23535552b385SBrandon     if (islite) {
23542a8381b2SBarry Smith       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSliteClose_Private));
23555552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Context", (PetscObject)contextObj));
23565552b385SBrandon     } else {
23572a8381b2SBarry Smith       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSClose_Private));
23589566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
23595552b385SBrandon     }
23609566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
2361c1cad2e7SMatthew G. Knepley   }
2362c1cad2e7SMatthew G. Knepley 
2363c1cad2e7SMatthew G. Knepley   // Label Points
23649566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
23659566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
23669566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
23679566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
23689566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
23699566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
23709566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
23719566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
2372c1cad2e7SMatthew G. Knepley 
2373c1cad2e7SMatthew G. Knepley   /* Get Number of DAG Nodes at each level */
2374c1cad2e7SMatthew G. Knepley   int fStart, fEnd, eStart, eEnd, nStart, nEnd;
2375c1cad2e7SMatthew G. Knepley 
23769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &fStart, &fEnd));
23779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &eStart, &eEnd));
23789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
2379c1cad2e7SMatthew G. Knepley 
2380c1cad2e7SMatthew G. Knepley   /* Set DMLabels for NODES */
2381c1cad2e7SMatthew G. Knepley   for (int n = nStart; n < nEnd; ++n) {
2382c1cad2e7SMatthew G. Knepley     int           pTypeVal, pIndexVal, pBodyVal;
2383c1cad2e7SMatthew G. Knepley     PetscHashIter PTLiter, PILiter, PBLiter;
2384c1cad2e7SMatthew G. Knepley     PetscBool     PTLfound, PILfound, PBLfound;
2385c1cad2e7SMatthew G. Knepley 
2386c1cad2e7SMatthew G. Knepley     //Converted to Hash Tables
23879566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pTypeLabelMap, n - nStart, &PTLiter, &PTLfound));
23885552b385SBrandon     PetscCheck(PTLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pTypeLabelMap", n);
23899566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pTypeLabelMap, n - nStart, &pTypeVal));
2390c1cad2e7SMatthew G. Knepley 
23919566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pIndexLabelMap, n - nStart, &PILiter, &PILfound));
23925552b385SBrandon     PetscCheck(PILfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pIndexLabelMap", n);
23939566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pIndexLabelMap, n - nStart, &pIndexVal));
2394c1cad2e7SMatthew G. Knepley 
23959566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pBodyIndexLabelMap, n - nStart, &PBLiter, &PBLfound));
23965552b385SBrandon     PetscCheck(PBLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pBodyLabelMap", n);
23979566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pBodyIndexLabelMap, n - nStart, &pBodyVal));
2398c1cad2e7SMatthew G. Knepley 
23999566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, n, pBodyVal));
24009566063dSJacob Faibussowitsch     if (pTypeVal == 0) PetscCall(DMLabelSetValue(vertexLabel, n, pIndexVal));
24019566063dSJacob Faibussowitsch     if (pTypeVal > 0) PetscCall(DMLabelSetValue(edgeLabel, n, pIndexVal));
24029566063dSJacob Faibussowitsch     if (pTypeVal < 0) PetscCall(DMLabelSetValue(faceLabel, n, pIndexVal));
2403c1cad2e7SMatthew G. Knepley   }
2404c1cad2e7SMatthew G. Knepley 
2405c1cad2e7SMatthew G. Knepley   /* Set DMLabels for Edges - Based on the DMLabels of the EDGE's NODES */
2406c1cad2e7SMatthew G. Knepley   for (int e = eStart; e < eEnd; ++e) {
2407c1cad2e7SMatthew G. Knepley     int bodyID_0, vertexID_0, vertexID_1, edgeID_0, edgeID_1, faceID_0, faceID_1;
2408c1cad2e7SMatthew G. Knepley 
24099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, e, &cone));
24109566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, cone[0], &bodyID_0)); // Do I need to check the other end?
24119566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, cone[0], &vertexID_0));
24129566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, cone[1], &vertexID_1));
24139566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, cone[0], &edgeID_0));
24149566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, cone[1], &edgeID_1));
24159566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, cone[0], &faceID_0));
24169566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, cone[1], &faceID_1));
2417c1cad2e7SMatthew G. Knepley 
24189566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, e, bodyID_0));
2419c1cad2e7SMatthew G. Knepley 
24209566063dSJacob Faibussowitsch     if (edgeID_0 == edgeID_1) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
24219566063dSJacob Faibussowitsch     else if (vertexID_0 > 0 && edgeID_1 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_1));
24229566063dSJacob Faibussowitsch     else if (vertexID_1 > 0 && edgeID_0 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
2423c1cad2e7SMatthew G. Knepley     else { /* Do Nothing */ }
2424c1cad2e7SMatthew G. Knepley   }
2425c1cad2e7SMatthew G. Knepley 
2426c1cad2e7SMatthew G. Knepley   /* Set DMLabels for Cells */
2427c1cad2e7SMatthew G. Knepley   for (int f = fStart; f < fEnd; ++f) {
2428c1cad2e7SMatthew G. Knepley     int           edgeID_0;
2429c1cad2e7SMatthew G. Knepley     PetscInt      triBodyVal, triFaceVal;
2430c1cad2e7SMatthew G. Knepley     PetscHashIter TFLiter, TBLiter;
2431c1cad2e7SMatthew G. Knepley     PetscBool     TFLfound, TBLfound;
2432c1cad2e7SMatthew G. Knepley 
2433c1cad2e7SMatthew G. Knepley     // Convert to Hash Table
24349566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(triFaceIDLabelMap, f - fStart, &TFLiter, &TFLfound));
24355552b385SBrandon     PetscCheck(TFLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in triFaceIDLabelMap", f);
24369566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(triFaceIDLabelMap, f - fStart, &triFaceVal));
2437c1cad2e7SMatthew G. Knepley 
24389566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(triBodyIDLabelMap, f - fStart, &TBLiter, &TBLfound));
24395552b385SBrandon     PetscCheck(TBLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in triBodyIDLabelMap", f);
24409566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(triBodyIDLabelMap, f - fStart, &triBodyVal));
2441c1cad2e7SMatthew G. Knepley 
24429566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, f, triBodyVal));
24439566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(faceLabel, f, triFaceVal));
2444c1cad2e7SMatthew G. Knepley 
2445c1cad2e7SMatthew G. Knepley     /* Finish Labeling previously unlabeled DMPlex Edges - Assumes Triangular Cell (3 Edges Max) */
24469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, f, &cone));
2447c1cad2e7SMatthew G. Knepley 
2448c1cad2e7SMatthew G. Knepley     for (int jj = 0; jj < 3; ++jj) {
24499566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(edgeLabel, cone[jj], &edgeID_0));
2450c1cad2e7SMatthew G. Knepley 
2451c1cad2e7SMatthew G. Knepley       if (edgeID_0 < 0) {
24529566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(bodyLabel, cone[jj], triBodyVal));
24539566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(faceLabel, cone[jj], triFaceVal));
2454c1cad2e7SMatthew G. Knepley       }
2455c1cad2e7SMatthew G. Knepley     }
2456c1cad2e7SMatthew G. Knepley   }
2457c1cad2e7SMatthew G. Knepley 
2458c1cad2e7SMatthew G. Knepley   *newdm = dm;
24593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2460c1cad2e7SMatthew G. Knepley }
24617bee2925SMatthew Knepley #endif
24627bee2925SMatthew Knepley 
24635552b385SBrandon /*@C
24645552b385SBrandon   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.
2465c1cad2e7SMatthew G. Knepley 
246620f4b53cSBarry Smith   Collective
2467c1cad2e7SMatthew G. Knepley 
2468c1cad2e7SMatthew G. Knepley   Input Parameter:
2469a1cb98faSBarry Smith . dm - The uninflated `DM` object representing the mesh
2470c1cad2e7SMatthew G. Knepley 
2471c1cad2e7SMatthew G. Knepley   Level: intermediate
2472c1cad2e7SMatthew G. Knepley 
24731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`
2474c1cad2e7SMatthew G. Knepley @*/
DMPlexInflateToGeomModelUseXYZ(DM dm)2475ce78bad3SBarry Smith PetscErrorCode DMPlexInflateToGeomModelUseXYZ(DM dm) PeNS
2476d71ae5a4SJacob Faibussowitsch {
2477ce78bad3SBarry Smith   // please don't fucking write code like this with #ifdef all of the place!
2478c1cad2e7SMatthew G. Knepley #if defined(PETSC_HAVE_EGADS)
2479c1cad2e7SMatthew G. Knepley   /* EGADS Variables */
24805552b385SBrandon   ego    model, geom, body, face, edge, vertex;
2481c1cad2e7SMatthew G. Knepley   ego   *bodies;
2482c1cad2e7SMatthew G. Knepley   int    Nb, oclass, mtype, *senses;
24835552b385SBrandon   double result[4];
2484c1cad2e7SMatthew G. Knepley   /* PETSc Variables */
2485c1cad2e7SMatthew G. Knepley   DM             cdm;
2486c1cad2e7SMatthew G. Knepley   PetscContainer modelObj;
2487c1cad2e7SMatthew G. Knepley   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
2488c1cad2e7SMatthew G. Knepley   Vec            coordinates;
2489c1cad2e7SMatthew G. Knepley   PetscScalar   *coords;
2490c1cad2e7SMatthew G. Knepley   PetscInt       bodyID, faceID, edgeID, vertexID;
2491c1cad2e7SMatthew G. Knepley   PetscInt       cdim, d, vStart, vEnd, v;
24925552b385SBrandon   PetscBool      islite = PETSC_FALSE;
2493c1cad2e7SMatthew G. Knepley #endif
2494c1cad2e7SMatthew G. Knepley 
2495c1cad2e7SMatthew G. Knepley   PetscFunctionBegin;
2496c1cad2e7SMatthew G. Knepley #if defined(PETSC_HAVE_EGADS)
24979566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
24985552b385SBrandon   if (!modelObj) {
24995552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
25005552b385SBrandon     islite = PETSC_TRUE;
25015552b385SBrandon   }
25023ba16761SJacob Faibussowitsch   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
25039566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
25049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
25059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
25069566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
25079566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
25089566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
25099566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
2510c1cad2e7SMatthew G. Knepley 
25112a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
25125552b385SBrandon 
25135552b385SBrandon   if (islite) {
25145552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25155552b385SBrandon   } else {
25169566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25175552b385SBrandon   }
2518c1cad2e7SMatthew G. Knepley 
25199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
25209566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(coordinates, &coords));
2521c1cad2e7SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
2522c1cad2e7SMatthew G. Knepley     PetscScalar *vcoords;
2523c1cad2e7SMatthew G. Knepley 
25249566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
25259566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
25269566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
25279566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
2528c1cad2e7SMatthew G. Knepley 
25295552b385SBrandon     PetscCheck(bodyID < Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bodyID, Nb);
25305552b385SBrandon     body = bodies[bodyID];
25315552b385SBrandon 
25325552b385SBrandon     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
25335552b385SBrandon     if (vertexID > 0) {
25345552b385SBrandon       if (islite) {
25355552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, NODE, vertexID, &vertex));
25365552b385SBrandon         PetscCall(EGlite_evaluate(vertex, NULL, result));
25375552b385SBrandon       } else {
25385552b385SBrandon         PetscCall(EG_objectBodyTopo(body, NODE, vertexID, &vertex));
25395552b385SBrandon         PetscCall(EG_evaluate(vertex, NULL, result));
25405552b385SBrandon       }
25415552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
25425552b385SBrandon     } else if (edgeID > 0) {
25435552b385SBrandon       /* Snap to EDGE at nearest location */
25445552b385SBrandon       double params[1];
25455552b385SBrandon       if (islite) {
25465552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
25475552b385SBrandon         PetscCall(EGlite_invEvaluate(edge, vcoords, params, result));
25485552b385SBrandon       } // Get (x,y,z) of nearest point on EDGE
25495552b385SBrandon       else {
25505552b385SBrandon         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
25515552b385SBrandon         PetscCall(EG_invEvaluate(edge, vcoords, params, result));
25525552b385SBrandon       }
25535552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
25545552b385SBrandon     } else if (faceID > 0) {
25555552b385SBrandon       /* Snap to FACE at nearest location */
25565552b385SBrandon       double params[2];
25575552b385SBrandon       if (islite) {
25585552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
25595552b385SBrandon         PetscCall(EGlite_invEvaluate(face, vcoords, params, result));
25605552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
25615552b385SBrandon       else {
25625552b385SBrandon         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
25635552b385SBrandon         PetscCall(EG_invEvaluate(face, vcoords, params, result));
25645552b385SBrandon       }
25655552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
25665552b385SBrandon     }
25675552b385SBrandon   }
25685552b385SBrandon   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
25695552b385SBrandon   /* Clear out global coordinates */
25705552b385SBrandon   PetscCall(VecDestroy(&dm->coordinates[0].x));
25715552b385SBrandon #endif
25725552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
25735552b385SBrandon }
25745552b385SBrandon 
25755552b385SBrandon #if defined(PETSC_HAVE_EGADS)
25765552b385SBrandon // This replaces the model in-place
ConvertGeomModelToAllBSplines(PetscBool islite,ego * model)2577ce78bad3SBarry Smith PetscErrorCode ConvertGeomModelToAllBSplines(PetscBool islite, ego *model) PeNS
25785552b385SBrandon {
25795552b385SBrandon   /* EGADS/EGADSlite Variables */
25805552b385SBrandon   ego  context = NULL, geom, *bodies, *fobjs;
25815552b385SBrandon   int  oclass, mtype;
25825552b385SBrandon   int *senses;
25835552b385SBrandon   int  Nb, Nf;
25845552b385SBrandon 
25855552b385SBrandon   PetscFunctionBegin;
25865552b385SBrandon   // Get the number of bodies and body objects in the model
25875552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (*model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25885552b385SBrandon   else PetscCallEGADS(EG_getTopology, (*model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25895552b385SBrandon 
25905552b385SBrandon   // Get all Faces on the body    <-- Only working with 1 body at the moment.
25915552b385SBrandon   ego body = bodies[0];
25925552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
25935552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
25945552b385SBrandon   ego newGeom[Nf];
25955552b385SBrandon   ego newFaces[Nf];
25965552b385SBrandon 
25975552b385SBrandon   // Convert the 1st Face to a BSpline Geometry
25985552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
25995552b385SBrandon     ego     face = fobjs[ii];
26005552b385SBrandon     ego     gRef, gPrev, gNext, *lobjs;
26015552b385SBrandon     int     goclass, gmtype, *gpinfo;
26025552b385SBrandon     int     Nl, *lsenses;
26035552b385SBrandon     double *gprv;
26045552b385SBrandon     char   *gClass = (char *)"", *gType = (char *)"";
26055552b385SBrandon 
26065552b385SBrandon     /* Shape Optimization is NOT available for EGADSlite geometry files. */
26075552b385SBrandon     /*     Note :: islite options are left below in case future versions of EGADSlite includes this capability */
26085552b385SBrandon     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");
26095552b385SBrandon 
26105552b385SBrandon     if (islite) {
26115552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses)); // Get FACES Geometry object (geom_
26125552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));            // Get geometry object info
26135552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
26145552b385SBrandon     } // Get geometry info
26155552b385SBrandon     else {
26165552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses)); // Get FACES Geometry object (geom_
26175552b385SBrandon       PetscCallEGADS(EG_getGeometry, (geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));            // Get geometry object info
26185552b385SBrandon       PetscCallEGADS(EG_getInfo, (geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
26195552b385SBrandon     } // Get geometry info
26205552b385SBrandon 
26215552b385SBrandon     PetscCall(DMPlex_EGADS_GeomDecode_Internal(goclass, gmtype, &gClass, &gType)); // Decode Geometry integers
26225552b385SBrandon 
26235552b385SBrandon     // Convert current FACE to a BSpline Surface
26245552b385SBrandon     ego     bspline;
26255552b385SBrandon     ego     bRef, bPrev, bNext;
26265552b385SBrandon     int     boclass, bmtype, *bpinfo;
26275552b385SBrandon     double *bprv;
26285552b385SBrandon     char   *bClass = (char *)"", *bType = (char *)"";
26295552b385SBrandon 
26305552b385SBrandon     PetscCallEGADS(EG_convertToBSpline, (face, &bspline)); // Does not have an EGlite_ version
26315552b385SBrandon 
26325552b385SBrandon     if (islite) {
26335552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (bspline, &boclass, &bmtype, &bRef, &bpinfo, &bprv)); // Get geometry object info
26345552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (bspline, &boclass, &bmtype, &bRef, &bPrev, &bNext));
26355552b385SBrandon     } // Get geometry info
26365552b385SBrandon     else {
26375552b385SBrandon       PetscCallEGADS(EG_getGeometry, (bspline, &boclass, &bmtype, &bRef, &bpinfo, &bprv)); // Get geometry object info
26385552b385SBrandon       PetscCallEGADS(EG_getInfo, (bspline, &boclass, &bmtype, &bRef, &bPrev, &bNext));
26395552b385SBrandon     } // Get geometry info
26405552b385SBrandon 
26415552b385SBrandon     PetscCall(DMPlex_EGADS_GeomDecode_Internal(boclass, bmtype, &bClass, &bType)); // Decode Geometry integers
26425552b385SBrandon 
26435552b385SBrandon     // Get Context from FACE
26445552b385SBrandon     context = NULL;
26455552b385SBrandon     PetscCallEGADS(EG_getContext, (face, &context)); // Does not have an EGlite_ version
26465552b385SBrandon 
26475552b385SBrandon     // Silence WARNING Regarding OPENCASCADE 7.5
26485552b385SBrandon     if (islite) PetscCallEGADS(EGlite_setOutLevel, (context, 0));
26495552b385SBrandon     else PetscCallEGADS(EG_setOutLevel, (context, 0));
26505552b385SBrandon 
26515552b385SBrandon     ego newgeom;
26525552b385SBrandon     PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, bprv, &newgeom)); // Does not have an EGlite_ version
26535552b385SBrandon 
26545552b385SBrandon     PetscCallEGADS(EG_deleteObject, (bspline));
26555552b385SBrandon 
26565552b385SBrandon     // Create new FACE based on new SURFACE geometry
26575552b385SBrandon     double data[4];
26585552b385SBrandon     int    periodic;
26595552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, data, &periodic));
26605552b385SBrandon     else PetscCallEGADS(EG_getRange, (newgeom, data, &periodic));
26615552b385SBrandon 
26625552b385SBrandon     ego newface;
26635552b385SBrandon     PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, data, &newface)); // Does not have an EGlite_ version
26645552b385SBrandon     //PetscCallEGADS(EG_deleteObject, (newgeom));
26655552b385SBrandon     //PetscCallEGADS(EG_deleteObject, (newface));
26665552b385SBrandon     newFaces[ii] = newface;
26675552b385SBrandon     newGeom[ii]  = newgeom;
26685552b385SBrandon 
26695552b385SBrandon     // Reinstate WARNING Regarding OPENCASCADE 7.5
26705552b385SBrandon     if (islite) PetscCallEGADS(EGlite_setOutLevel, (context, 1));
26715552b385SBrandon     else PetscCallEGADS(EG_setOutLevel, (context, 1));
26725552b385SBrandon   }
26735552b385SBrandon 
26745552b385SBrandon   // Sew New Faces together to get a new model
26755552b385SBrandon   ego newmodel;
26765552b385SBrandon   PetscCallEGADS(EG_sewFaces, (Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version
26775552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
26785552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newFaces[ii]));
26795552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newGeom[ii]));
26805552b385SBrandon   }
26815552b385SBrandon   PetscCallEGADS(EG_deleteObject, (*model));
26825552b385SBrandon   *model = newmodel;
26835552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
26845552b385SBrandon }
26855552b385SBrandon #endif
26865552b385SBrandon 
26875552b385SBrandon /*@C
26885552b385SBrandon   DMPlexCreateGeomFromFile - Create a `DMPLEX` mesh from an EGADS, IGES, or STEP file.
26895552b385SBrandon 
26905552b385SBrandon   Collective
26915552b385SBrandon 
26925552b385SBrandon   Input Parameters:
26935552b385SBrandon + comm     - The MPI communicator
26945552b385SBrandon . filename - The name of the EGADS, IGES, or STEP file
26955552b385SBrandon - islite   - Flag for EGADSlite support
26965552b385SBrandon 
26975552b385SBrandon   Output Parameter:
26985552b385SBrandon . dm - The `DM` object representing the mesh
26995552b385SBrandon 
27005552b385SBrandon   Level: beginner
27015552b385SBrandon 
27025552b385SBrandon .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`, `DMPlexCreateEGADSliteFromFile()`
27035552b385SBrandon @*/
DMPlexCreateGeomFromFile(MPI_Comm comm,const char filename[],DM * dm,PetscBool islite)2704ce78bad3SBarry Smith PetscErrorCode DMPlexCreateGeomFromFile(MPI_Comm comm, const char filename[], DM *dm, PetscBool islite) PeNS
27055552b385SBrandon {
27065552b385SBrandon   /* PETSc Variables */
27075552b385SBrandon   PetscMPIInt rank;
27085552b385SBrandon   PetscBool   printModel = PETSC_FALSE, tessModel = PETSC_FALSE, newModel = PETSC_FALSE;
27095552b385SBrandon   PetscBool   shapeOpt = PETSC_FALSE;
27105552b385SBrandon 
27115552b385SBrandon #if defined(PETSC_HAVE_EGADS)
27125552b385SBrandon   ego context = NULL, model = NULL;
27135552b385SBrandon #endif
27145552b385SBrandon 
27155552b385SBrandon   PetscFunctionBegin;
27165552b385SBrandon   PetscAssertPointer(filename, 2);
27175552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_print_model", &printModel, NULL));
27185552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_tess_model", &tessModel, NULL));
27195552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_new_model", &newModel, NULL));
27205552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_shape_opt", &shapeOpt, NULL));
27215552b385SBrandon   PetscCallMPI(MPI_Comm_rank(comm, &rank));
27225552b385SBrandon #if defined(PETSC_HAVE_EGADS)
27235552b385SBrandon   if (rank == 0) {
27245552b385SBrandon     /* EGADSlite files cannot be used for Shape Optimization Work. It lacks the ability to make new geometry. */
27255552b385SBrandon     /* Must use EGADS, STEP, IGES or BRep files to perform this work.                                         */
27265552b385SBrandon     if (islite) {
27275552b385SBrandon       PetscCallEGADS(EGlite_open, (&context));
27285552b385SBrandon       PetscCallEGADS(EGlite_loadModel, (context, 0, filename, &model));
27295552b385SBrandon       if (shapeOpt) PetscCall(ConvertGeomModelToAllBSplines(islite, &model));
27305552b385SBrandon       if (printModel) PetscCall(DMPlexGeomPrintModel_Internal(model, islite));
27315552b385SBrandon     } else {
27325552b385SBrandon       PetscCallEGADS(EG_open, (&context));
27335552b385SBrandon       PetscCallEGADS(EG_loadModel, (context, 0, filename, &model));
27345552b385SBrandon       if (shapeOpt) PetscCall(ConvertGeomModelToAllBSplines(islite, &model));
27355552b385SBrandon       if (printModel) PetscCall(DMPlexGeomPrintModel_Internal(model, islite));
27365552b385SBrandon     }
27375552b385SBrandon   }
27385552b385SBrandon   if (tessModel) PetscCall(DMPlexCreateGeom_Tess_Internal(comm, context, model, dm, islite));
27395552b385SBrandon   else if (newModel) PetscCall(DMPlexCreateGeom_Internal(comm, context, model, dm, islite));
27403a7d0413SPierre Jolivet   else PetscCall(DMPlexCreateGeom(comm, context, model, dm, islite));
27415552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
27425552b385SBrandon #else
27435552b385SBrandon   SETERRQ(comm, PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
27445552b385SBrandon #endif
27455552b385SBrandon }
27465552b385SBrandon 
27475552b385SBrandon #if defined(PETSC_HAVE_EGADS)
27485552b385SBrandon /*@C
27495552b385SBrandon   DMPlex_Surface_Grad - Exposes the Geometry's Control Points and Weights and Calculates the Mesh Topology Boundary Nodes Gradient
27505552b385SBrandon                         with respect the associated geometry's Control Points and Weights.
27515552b385SBrandon 
27525552b385SBrandon                         // ----- Depreciated ---- See DMPlexGeomDataAndGrads ------ //
27535552b385SBrandon 
27545552b385SBrandon   Collective
27555552b385SBrandon 
27565552b385SBrandon   Input Parameters:
27575552b385SBrandon . dm      - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
27585552b385SBrandon 
27595552b385SBrandon   Output Parameter:
27605552b385SBrandon . 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
27615552b385SBrandon 
27625552b385SBrandon   Level: intermediate
27635552b385SBrandon 
27645552b385SBrandon .seealso:
27655552b385SBrandon @*/
DMPlex_Surface_Grad(DM dm)27665552b385SBrandon PetscErrorCode DMPlex_Surface_Grad(DM dm)
27675552b385SBrandon {
27685552b385SBrandon   ego            model, geom, *bodies, *fobjs;
27695552b385SBrandon   PetscContainer modelObj;
27705552b385SBrandon   int            oclass, mtype, *senses;
27715552b385SBrandon   int            Nb, Nf;
27725552b385SBrandon   PetscHMapI     faceCntrlPtRow_Start = NULL, faceCPWeightsRow_Start = NULL;
27735552b385SBrandon   PetscHMapI     pointSurfGradRow_Start = NULL;
27745552b385SBrandon   Mat            pointSurfGrad;
27755552b385SBrandon   IS             faceLabelValues, edgeLabelValues, vertexLabelValues;
27765552b385SBrandon   PetscInt       faceLabelSize, edgeLabelSize, vertexLabelSize;
27775552b385SBrandon   PetscBool      islite = PETSC_FALSE;
27785552b385SBrandon 
27795552b385SBrandon   PetscFunctionBegin;
27805552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
27815552b385SBrandon   if (!modelObj) {
27825552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
27835552b385SBrandon     islite = PETSC_TRUE;
27845552b385SBrandon     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");
27855552b385SBrandon   }
27865552b385SBrandon 
27875552b385SBrandon   // Get attached EGADS model (pointer)
27882a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
27895552b385SBrandon 
27905552b385SBrandon   // Get the bodies in the model
27915552b385SBrandon   if (islite) {
27925552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
27935552b385SBrandon   } else {
27945552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
27955552b385SBrandon   }
27965552b385SBrandon 
27975552b385SBrandon   ego body = bodies[0]; // Only operate on 1st body. Model should only have 1 body.
27985552b385SBrandon 
27995552b385SBrandon   // Get the total number of FACEs in the model
28005552b385SBrandon   if (islite) {
28015552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
28025552b385SBrandon   } else {
28035552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
28045552b385SBrandon   }
28055552b385SBrandon 
28065552b385SBrandon   // Get the total number of points and IDs in the DMPlex with a "EGADS Face Label"
28075552b385SBrandon   // This will provide the total number of DMPlex points on the boundary of the geometry
28085552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Face ID", &faceLabelValues));
28095552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Face ID", &faceLabelSize));
28105552b385SBrandon 
28115552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Edge ID", &edgeLabelValues));
28125552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Edge ID", &edgeLabelSize));
28135552b385SBrandon 
28145552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Vertex ID", &vertexLabelValues));
28155552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Vertex ID", &vertexLabelSize));
28165552b385SBrandon 
28175552b385SBrandon   const PetscInt *faceIndices, *edgeIndices, *vertexIndices;
28185552b385SBrandon   PetscCall(ISGetIndices(faceLabelValues, &faceIndices));
28195552b385SBrandon   PetscCall(ISGetIndices(edgeLabelValues, &edgeIndices));
28205552b385SBrandon   PetscCall(ISGetIndices(vertexLabelValues, &vertexIndices));
28215552b385SBrandon 
28225552b385SBrandon   // Get the points associated with each FACE, EDGE and VERTEX label in the DM
28235552b385SBrandon   PetscInt totalNumPoints = 0;
28245552b385SBrandon   for (int ii = 0; ii < faceLabelSize; ++ii) {
28255552b385SBrandon     // Cycle through FACE labels
28265552b385SBrandon     PetscInt size;
28275552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Face ID", faceIndices[ii], &size));
28285552b385SBrandon     totalNumPoints += size;
28295552b385SBrandon   }
28305552b385SBrandon   PetscCall(ISRestoreIndices(faceLabelValues, &faceIndices));
28315552b385SBrandon   PetscCall(ISDestroy(&faceLabelValues));
28325552b385SBrandon 
28335552b385SBrandon   for (int ii = 0; ii < edgeLabelSize; ++ii) {
28345552b385SBrandon     // Cycle Through EDGE Labels
28355552b385SBrandon     PetscInt size;
28365552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Edge ID", edgeIndices[ii], &size));
28375552b385SBrandon     totalNumPoints += size;
28385552b385SBrandon   }
28395552b385SBrandon   PetscCall(ISRestoreIndices(edgeLabelValues, &edgeIndices));
28405552b385SBrandon   PetscCall(ISDestroy(&edgeLabelValues));
28415552b385SBrandon 
28425552b385SBrandon   for (int ii = 0; ii < vertexLabelSize; ++ii) {
28435552b385SBrandon     // Cycle Through VERTEX Labels
28445552b385SBrandon     PetscInt size;
28455552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Vertex ID", vertexIndices[ii], &size));
28465552b385SBrandon     totalNumPoints += size;
28475552b385SBrandon   }
28485552b385SBrandon   PetscCall(ISRestoreIndices(vertexLabelValues, &vertexIndices));
28495552b385SBrandon   PetscCall(ISDestroy(&vertexLabelValues));
28505552b385SBrandon 
28515552b385SBrandon   int     maxNumCPs   = 0;
28525552b385SBrandon   int     totalNumCPs = 0;
28535552b385SBrandon   ego     bRef, bPrev, bNext, fgeom, *lobjs;
28545552b385SBrandon   int     id, boclass, bmtype, *bpinfo;
28555552b385SBrandon   int     foclass, fmtype, Nl, *lsenses;
28565552b385SBrandon   double *bprv;
28575552b385SBrandon   double  fdata[4];
28585552b385SBrandon 
28595552b385SBrandon   // Create Hash Tables
28605552b385SBrandon   PetscInt cntr = 0, wcntr = 0;
28615552b385SBrandon   PetscCall(PetscHMapICreate(&faceCntrlPtRow_Start));
28625552b385SBrandon   PetscCall(PetscHMapICreate(&faceCPWeightsRow_Start));
28635552b385SBrandon 
28645552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
28655552b385SBrandon     // Need to get the maximum number of Control Points defining the FACEs
28665552b385SBrandon     ego face = fobjs[ii];
28675552b385SBrandon     int maxNumCPs_temp;
28685552b385SBrandon 
28695552b385SBrandon     if (islite) {
28705552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
28715552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
28725552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
28735552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
28745552b385SBrandon     } else {
28755552b385SBrandon       id = EG_indexBodyTopo(body, face);
28765552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
28775552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
28785552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
28795552b385SBrandon     }
28805552b385SBrandon 
28815552b385SBrandon     maxNumCPs_temp = bpinfo[2] * bpinfo[5];
28825552b385SBrandon     totalNumCPs += bpinfo[2] * bpinfo[5];
28835552b385SBrandon 
2884ac530a7eSPierre Jolivet     if (maxNumCPs_temp > maxNumCPs) maxNumCPs = maxNumCPs_temp;
28855552b385SBrandon   }
28865552b385SBrandon 
28875552b385SBrandon   PetscInt *cpCoordDataLengthPtr, *wDataLengthPtr;
28885552b385SBrandon   PetscInt  cpCoordDataLength = 3 * totalNumCPs;
28895552b385SBrandon   PetscInt  wDataLength       = totalNumCPs;
28905552b385SBrandon   cpCoordDataLengthPtr        = &cpCoordDataLength;
28915552b385SBrandon   wDataLengthPtr              = &wDataLength;
28925552b385SBrandon   PetscScalar *cntrlPtCoords, *cntrlPtWeights;
28935552b385SBrandon   PetscMalloc1(cpCoordDataLength, &cntrlPtCoords);
28945552b385SBrandon   PetscMalloc1(wDataLength, &cntrlPtWeights);
28955552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
28965552b385SBrandon     // Need to Populate Control Point Coordinates and Weight Vectors
28975552b385SBrandon     ego           face = fobjs[ii];
28985552b385SBrandon     PetscHashIter hashKeyIter, wHashKeyIter;
28995552b385SBrandon     PetscBool     hashKeyFound, wHashKeyFound;
29005552b385SBrandon 
29015552b385SBrandon     if (islite) {
29025552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
29035552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
29045552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
29055552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
29065552b385SBrandon     } else {
29075552b385SBrandon       id = EG_indexBodyTopo(body, face);
29085552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
29095552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
29105552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
29115552b385SBrandon     }
29125552b385SBrandon 
29135552b385SBrandon     // Store Face ID to 1st Row of Control Point Vector
29145552b385SBrandon     PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, id, &hashKeyIter, &hashKeyFound));
29155552b385SBrandon 
29163a7d0413SPierre Jolivet     if (!hashKeyFound) PetscCall(PetscHMapISet(faceCntrlPtRow_Start, id, cntr));
29175552b385SBrandon 
29185552b385SBrandon     int offsetCoord = bpinfo[3] + bpinfo[6];
29195552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; ++jj) {
29205552b385SBrandon       cntrlPtCoords[cntr] = bprv[offsetCoord + jj];
29215552b385SBrandon       cntr += 1;
29225552b385SBrandon     }
29235552b385SBrandon 
29245552b385SBrandon     // Store Face ID to 1st Row of Control Point Weight Vector
29255552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, id, &wHashKeyIter, &wHashKeyFound));
29265552b385SBrandon 
29273a7d0413SPierre Jolivet     if (!wHashKeyFound) PetscCall(PetscHMapISet(faceCPWeightsRow_Start, id, wcntr));
29285552b385SBrandon 
29295552b385SBrandon     int offsetWeight = bpinfo[3] + bpinfo[6] + (3 * bpinfo[2] * bpinfo[5]);
29305552b385SBrandon     for (int jj = 0; jj < bpinfo[2] * bpinfo[5]; ++jj) {
29315552b385SBrandon       cntrlPtWeights[wcntr] = bprv[offsetWeight + jj];
29325552b385SBrandon       wcntr += 1;
29335552b385SBrandon     }
29345552b385SBrandon   }
29355552b385SBrandon 
29365552b385SBrandon   // Attach Control Point and Weight Data to DM
29375552b385SBrandon   {
29385552b385SBrandon     PetscContainer cpOrgObj, cpCoordObj, cpCoordLengthObj;
29395552b385SBrandon     PetscContainer wOrgObj, wValObj, wDataLengthObj;
29405552b385SBrandon 
29415552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpOrgObj));
29425552b385SBrandon     PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
29435552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Hash Table", (PetscObject)cpOrgObj));
29445552b385SBrandon     PetscCall(PetscContainerDestroy(&cpOrgObj));
29455552b385SBrandon 
29465552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordObj));
29475552b385SBrandon     PetscCall(PetscContainerSetPointer(cpCoordObj, cntrlPtCoords));
29485552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinates", (PetscObject)cpCoordObj));
29495552b385SBrandon     PetscCall(PetscContainerDestroy(&cpCoordObj));
29505552b385SBrandon 
29515552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordLengthObj));
29525552b385SBrandon     PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
29535552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject)cpCoordLengthObj));
29545552b385SBrandon     PetscCall(PetscContainerDestroy(&cpCoordLengthObj));
29555552b385SBrandon 
29565552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wOrgObj));
29575552b385SBrandon     PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
29585552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject)wOrgObj));
29595552b385SBrandon     PetscCall(PetscContainerDestroy(&wOrgObj));
29605552b385SBrandon 
29615552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wValObj));
29625552b385SBrandon     PetscCall(PetscContainerSetPointer(wValObj, cntrlPtWeights));
29635552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data", (PetscObject)wValObj));
29645552b385SBrandon     PetscCall(PetscContainerDestroy(&wValObj));
29655552b385SBrandon 
29665552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wDataLengthObj));
29675552b385SBrandon     PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
29685552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data Length", (PetscObject)wDataLengthObj));
29695552b385SBrandon     PetscCall(PetscContainerDestroy(&wDataLengthObj));
29705552b385SBrandon   }
29715552b385SBrandon 
29725552b385SBrandon   // Define Matrix to store  Surface Gradient information dx_i/dCPj_i
29735552b385SBrandon   PetscInt       gcntr   = 0;
29745552b385SBrandon   const PetscInt rowSize = 3 * maxNumCPs * totalNumPoints;
29755552b385SBrandon   const PetscInt colSize = 4 * Nf;
29765552b385SBrandon 
29775552b385SBrandon   // Create Point Surface Gradient Matrix
29785552b385SBrandon   MatCreate(PETSC_COMM_WORLD, &pointSurfGrad);
29795552b385SBrandon   MatSetSizes(pointSurfGrad, PETSC_DECIDE, PETSC_DECIDE, rowSize, colSize);
29805552b385SBrandon   MatSetType(pointSurfGrad, MATAIJ);
29815552b385SBrandon   MatSetUp(pointSurfGrad);
29825552b385SBrandon 
29835552b385SBrandon   // Create Hash Table to store Point's stare row in surfaceGrad[][]
29845552b385SBrandon   PetscCall(PetscHMapICreate(&pointSurfGradRow_Start));
29855552b385SBrandon 
29865552b385SBrandon   // Get Coordinates for the DMPlex point
29875552b385SBrandon   DM           cdm;
29885552b385SBrandon   PetscInt     dE, Nv;
29895552b385SBrandon   Vec          coordinatesLocal;
29905552b385SBrandon   PetscScalar *coords = NULL;
29915552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
29925552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &dE));
29935552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
29945552b385SBrandon 
29955552b385SBrandon   // CYCLE THROUGH FACEs
29965552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
29975552b385SBrandon     ego             face = fobjs[ii];
29985552b385SBrandon     ego            *eobjs, *nobjs;
29995552b385SBrandon     PetscInt        fid, Ne, Nn;
30005552b385SBrandon     DMLabel         faceLabel, edgeLabel, nodeLabel;
30015552b385SBrandon     PetscHMapI      currFaceUniquePoints = NULL;
30025552b385SBrandon     IS              facePoints, edgePoints, nodePoints;
30035552b385SBrandon     const PetscInt *fIndices, *eIndices, *nIndices;
30045552b385SBrandon     PetscInt        fSize, eSize, nSize;
30055552b385SBrandon     PetscHashIter   fHashKeyIter, eHashKeyIter, nHashKeyIter, pHashKeyIter;
30065552b385SBrandon     PetscBool       fHashKeyFound, eHashKeyFound, nHashKeyFound, pHashKeyFound;
30075552b385SBrandon     PetscInt        cfCntr = 0;
30085552b385SBrandon 
30095552b385SBrandon     // Get Geometry Object for the Current FACE
30105552b385SBrandon     if (islite) {
30115552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
30125552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
30135552b385SBrandon     } else {
30145552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
30155552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
30165552b385SBrandon     }
30175552b385SBrandon 
30185552b385SBrandon     // Get all EDGE and NODE objects attached to the current FACE
30195552b385SBrandon     if (islite) {
30205552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
30215552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, NODE, &Nn, &nobjs));
30225552b385SBrandon     } else {
30235552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
30245552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, NODE, &Nn, &nobjs));
30255552b385SBrandon     }
30265552b385SBrandon 
30275552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Face ID" and store them in a Hash Table for later use
30285552b385SBrandon     if (islite) {
30295552b385SBrandon       fid = EGlite_indexBodyTopo(body, face);
30305552b385SBrandon     } else {
30315552b385SBrandon       fid = EG_indexBodyTopo(body, face);
30325552b385SBrandon     }
30335552b385SBrandon 
30345552b385SBrandon     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
30355552b385SBrandon     PetscCall(DMLabelGetStratumIS(faceLabel, fid, &facePoints));
30365552b385SBrandon     PetscCall(ISGetIndices(facePoints, &fIndices));
30375552b385SBrandon     PetscCall(ISGetSize(facePoints, &fSize));
30385552b385SBrandon 
30395552b385SBrandon     PetscCall(PetscHMapICreate(&currFaceUniquePoints));
30405552b385SBrandon 
30415552b385SBrandon     for (int jj = 0; jj < fSize; ++jj) {
30425552b385SBrandon       PetscCall(PetscHMapIFind(currFaceUniquePoints, fIndices[jj], &fHashKeyIter, &fHashKeyFound));
30435552b385SBrandon 
30445552b385SBrandon       if (!fHashKeyFound) {
30455552b385SBrandon         PetscCall(PetscHMapISet(currFaceUniquePoints, fIndices[jj], cfCntr));
30465552b385SBrandon         cfCntr += 1;
30475552b385SBrandon       }
30485552b385SBrandon 
30495552b385SBrandon       PetscCall(PetscHMapIFind(pointSurfGradRow_Start, fIndices[jj], &pHashKeyIter, &pHashKeyFound));
30505552b385SBrandon 
30515552b385SBrandon       if (!pHashKeyFound) {
30525552b385SBrandon         PetscCall(PetscHMapISet(pointSurfGradRow_Start, fIndices[jj], gcntr));
30535552b385SBrandon         gcntr += 3 * maxNumCPs;
30545552b385SBrandon       }
30555552b385SBrandon     }
30565552b385SBrandon     PetscCall(ISRestoreIndices(facePoints, &fIndices));
30575552b385SBrandon     PetscCall(ISDestroy(&facePoints));
30585552b385SBrandon 
30595552b385SBrandon     // 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.
30605552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
30615552b385SBrandon       ego       edge = eobjs[jj];
30625552b385SBrandon       PetscBool containLabelValue;
30635552b385SBrandon 
30645552b385SBrandon       if (islite) {
30655552b385SBrandon         id = EGlite_indexBodyTopo(body, edge);
30665552b385SBrandon       } else {
30675552b385SBrandon         id = EG_indexBodyTopo(body, edge);
30685552b385SBrandon       }
30695552b385SBrandon 
30705552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
30715552b385SBrandon       PetscCall(DMLabelHasValue(edgeLabel, id, &containLabelValue));
30725552b385SBrandon 
30735552b385SBrandon       if (containLabelValue) {
30745552b385SBrandon         PetscCall(DMLabelGetStratumIS(edgeLabel, id, &edgePoints));
30755552b385SBrandon         PetscCall(ISGetIndices(edgePoints, &eIndices));
30765552b385SBrandon         PetscCall(ISGetSize(edgePoints, &eSize));
30775552b385SBrandon 
30785552b385SBrandon         for (int kk = 0; kk < eSize; ++kk) {
30795552b385SBrandon           PetscCall(PetscHMapIFind(currFaceUniquePoints, eIndices[kk], &eHashKeyIter, &eHashKeyFound));
30805552b385SBrandon 
30815552b385SBrandon           if (!eHashKeyFound) {
30825552b385SBrandon             PetscCall(PetscHMapISet(currFaceUniquePoints, eIndices[kk], cfCntr));
30835552b385SBrandon             cfCntr += 1;
30845552b385SBrandon           }
30855552b385SBrandon 
30865552b385SBrandon           PetscCall(PetscHMapIFind(pointSurfGradRow_Start, eIndices[kk], &pHashKeyIter, &pHashKeyFound));
30875552b385SBrandon 
30885552b385SBrandon           if (!pHashKeyFound) {
30895552b385SBrandon             PetscCall(PetscHMapISet(pointSurfGradRow_Start, eIndices[kk], gcntr));
30905552b385SBrandon             gcntr += 3 * maxNumCPs;
30915552b385SBrandon           }
30925552b385SBrandon         }
30935552b385SBrandon         PetscCall(ISRestoreIndices(edgePoints, &eIndices));
30945552b385SBrandon         PetscCall(ISDestroy(&edgePoints));
30955552b385SBrandon       }
30965552b385SBrandon     }
30975552b385SBrandon 
30985552b385SBrandon     // 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.
30995552b385SBrandon     for (int jj = 0; jj < Nn; ++jj) {
31005552b385SBrandon       ego node = nobjs[jj];
31015552b385SBrandon 
31025552b385SBrandon       if (islite) {
31035552b385SBrandon         id = EGlite_indexBodyTopo(body, node);
31045552b385SBrandon       } else {
31055552b385SBrandon         id = EG_indexBodyTopo(body, node);
31065552b385SBrandon       }
31075552b385SBrandon 
31085552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &nodeLabel));
31095552b385SBrandon       PetscCall(DMLabelGetStratumIS(nodeLabel, id, &nodePoints));
31105552b385SBrandon       PetscCall(ISGetIndices(nodePoints, &nIndices));
31115552b385SBrandon       PetscCall(ISGetSize(nodePoints, &nSize));
31125552b385SBrandon 
31135552b385SBrandon       for (int kk = 0; kk < nSize; ++kk) {
31145552b385SBrandon         PetscCall(PetscHMapIFind(currFaceUniquePoints, nIndices[kk], &nHashKeyIter, &nHashKeyFound));
31155552b385SBrandon 
31165552b385SBrandon         if (!nHashKeyFound) {
31175552b385SBrandon           PetscCall(PetscHMapISet(currFaceUniquePoints, nIndices[kk], cfCntr));
31185552b385SBrandon           cfCntr += 1;
31195552b385SBrandon         }
31205552b385SBrandon 
31215552b385SBrandon         PetscCall(PetscHMapIFind(pointSurfGradRow_Start, nIndices[kk], &pHashKeyIter, &pHashKeyFound));
31225552b385SBrandon         if (!pHashKeyFound) {
31235552b385SBrandon           PetscCall(PetscHMapISet(pointSurfGradRow_Start, nIndices[kk], gcntr));
31245552b385SBrandon           gcntr += 3 * maxNumCPs;
31255552b385SBrandon         }
31265552b385SBrandon       }
31275552b385SBrandon       PetscCall(ISRestoreIndices(nodePoints, &nIndices));
31285552b385SBrandon       PetscCall(ISDestroy(&nodePoints));
31295552b385SBrandon     }
31305552b385SBrandon 
31315552b385SBrandon     // Get the Total Number of entries in the Hash Table
31325552b385SBrandon     PetscInt currFaceUPSize;
31335552b385SBrandon     PetscCall(PetscHMapIGetSize(currFaceUniquePoints, &currFaceUPSize));
31345552b385SBrandon 
31355552b385SBrandon     // Get Keys
31365552b385SBrandon     PetscInt currFaceUPKeys[currFaceUPSize], off = 0;
31375552b385SBrandon     PetscCall(PetscHMapIGetKeys(currFaceUniquePoints, &off, currFaceUPKeys));
31385552b385SBrandon 
31395552b385SBrandon     // Cycle through all points on the current FACE
31405552b385SBrandon     for (int jj = 0; jj < currFaceUPSize; ++jj) {
31415552b385SBrandon       PetscInt currPointID = currFaceUPKeys[jj];
31425552b385SBrandon       PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
31435552b385SBrandon 
31445552b385SBrandon       // Get UV position of FACE
31455552b385SBrandon       double params[2], range[4], eval[18];
31465552b385SBrandon       int    peri;
31475552b385SBrandon 
31485552b385SBrandon       if (islite) {
31495552b385SBrandon         PetscCall(EGlite_getRange(face, range, &peri));
31505552b385SBrandon       } else {
31515552b385SBrandon         PetscCall(EG_getRange(face, range, &peri));
31525552b385SBrandon       }
31535552b385SBrandon 
31545552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
31555552b385SBrandon 
31565552b385SBrandon       if (islite) {
31575552b385SBrandon         PetscCall(EGlite_evaluate(face, params, eval));
31585552b385SBrandon       } else {
31595552b385SBrandon         PetscCall(EG_evaluate(face, params, eval));
31605552b385SBrandon       }
31615552b385SBrandon 
31625552b385SBrandon       // Make a new SURFACE Geometry by changing the location of the Control Points
31635552b385SBrandon       int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
31645552b385SBrandon       double nbprv[prvSize];
31655552b385SBrandon 
31665552b385SBrandon       // Cycle through each Control Point
31675552b385SBrandon       double deltaCoord = 1.0E-4;
31685552b385SBrandon       int    offset     = bpinfo[3] + bpinfo[6];
31695552b385SBrandon       int    wOffset    = offset + (3 * bpinfo[2] * bpinfo[5]);
31705552b385SBrandon       for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) {
31715552b385SBrandon         // Cycle through each direction (x, then y, then z)
31725552b385SBrandon         for (int kk = 0; kk < 4; ++kk) {
31735552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
3174ac530a7eSPierre Jolivet           for (int mm = 0; mm < prvSize; ++mm) nbprv[mm] = bprv[mm];
31755552b385SBrandon 
31765552b385SBrandon           if (kk == 0) { //X
31775552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0] + deltaCoord;
31785552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
31795552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
31805552b385SBrandon           } else if (kk == 1) { //Y
31815552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
31825552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1] + deltaCoord;
31835552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
31845552b385SBrandon           } else if (kk == 2) { //Z
31855552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
31865552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
31875552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2] + deltaCoord;
31885552b385SBrandon           } else if (kk == 3) { // Weights
31895552b385SBrandon             nbprv[wOffset + ii] = bprv[wOffset + ii] + deltaCoord;
31905552b385SBrandon           } else {
31915552b385SBrandon             // currently do nothing
31925552b385SBrandon           }
31935552b385SBrandon 
31945552b385SBrandon           // Create New Surface Based on New Control Points or Weights
31955552b385SBrandon           ego newgeom, context;
31965552b385SBrandon           if (islite) {
31975552b385SBrandon             PetscCall(EGlite_open(&context));
31985552b385SBrandon             PetscCall(EGlite_setOutLevel(context, 0));
31995552b385SBrandon           } else {
32005552b385SBrandon             PetscCall(EG_open(&context));
32015552b385SBrandon             PetscCall(EG_setOutLevel(context, 0));
32025552b385SBrandon           }
32035552b385SBrandon 
32045552b385SBrandon           PetscCall(EG_makeGeometry(context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
32055552b385SBrandon 
32065552b385SBrandon           if (islite) {
32075552b385SBrandon             PetscCall(EGlite_setOutLevel(context, 1));
32085552b385SBrandon           } else {
32095552b385SBrandon             PetscCall(EG_setOutLevel(context, 1));
32105552b385SBrandon           }
32115552b385SBrandon 
32125552b385SBrandon           // Evaluate new (x, y, z) Point Position based on new Surface Definition
32135552b385SBrandon           double newCoords[18];
32145552b385SBrandon           if (islite) {
32155552b385SBrandon             PetscCall(EGlite_getRange(newgeom, range, &peri));
32165552b385SBrandon           } else {
32175552b385SBrandon             PetscCall(EG_getRange(newgeom, range, &peri));
32185552b385SBrandon           }
32195552b385SBrandon 
32205552b385SBrandon           PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, newgeom, range, 0, dE, params, islite));
32215552b385SBrandon 
32225552b385SBrandon           if (islite) {
32235552b385SBrandon             PetscCall(EGlite_evaluate(newgeom, params, newCoords));
32245552b385SBrandon           } else {
32255552b385SBrandon             PetscCall(EG_evaluate(newgeom, params, newCoords));
32265552b385SBrandon           }
32275552b385SBrandon 
32285552b385SBrandon           // Now Calculate the Surface Gradient for the change in x-component Control Point
32295552b385SBrandon           PetscScalar dxdCx = (newCoords[0] - coords[0]) / deltaCoord;
32305552b385SBrandon           PetscScalar dxdCy = (newCoords[1] - coords[1]) / deltaCoord;
32315552b385SBrandon           PetscScalar dxdCz = (newCoords[2] - coords[2]) / deltaCoord;
32325552b385SBrandon 
32335552b385SBrandon           // Store Gradient Information in surfaceGrad[][] Matrix
32345552b385SBrandon           PetscInt startRow;
32355552b385SBrandon           PetscCall(PetscHMapIGet(pointSurfGradRow_Start, currPointID, &startRow));
32365552b385SBrandon 
3237f0b74427SPierre Jolivet           // Store Results in PETSc Mat
32385552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 0, ((fid - 1) * 4) + kk, dxdCx, INSERT_VALUES));
32395552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 1, ((fid - 1) * 4) + kk, dxdCy, INSERT_VALUES));
32405552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 2, ((fid - 1) * 4) + kk, dxdCz, INSERT_VALUES));
32415552b385SBrandon         }
32425552b385SBrandon         offset += 3;
32435552b385SBrandon       }
32445552b385SBrandon       PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
32455552b385SBrandon     }
32465552b385SBrandon   }
32475552b385SBrandon 
32485552b385SBrandon   // Assemble Point Surface Grad Matrix
32495552b385SBrandon   MatAssemblyBegin(pointSurfGrad, MAT_FINAL_ASSEMBLY);
32505552b385SBrandon   MatAssemblyEnd(pointSurfGrad, MAT_FINAL_ASSEMBLY);
32515552b385SBrandon 
32525552b385SBrandon   // Attach Surface Gradient Hash Table and Matrix to DM
32535552b385SBrandon   {
32545552b385SBrandon     PetscContainer surfGradOrgObj, surfGradObj;
32555552b385SBrandon 
32565552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradOrgObj));
32575552b385SBrandon     PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
32585552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject)surfGradOrgObj));
32595552b385SBrandon     PetscCall(PetscContainerDestroy(&surfGradOrgObj));
32605552b385SBrandon 
32615552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradObj));
32625552b385SBrandon     PetscCall(PetscContainerSetPointer(surfGradObj, pointSurfGrad));
32635552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Matrix", (PetscObject)surfGradObj));
32645552b385SBrandon     PetscCall(PetscContainerDestroy(&surfGradObj));
32655552b385SBrandon   }
32665552b385SBrandon   if (islite) EGlite_free(fobjs);
32675552b385SBrandon   else EG_free(fobjs);
32685552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
32695552b385SBrandon }
32705552b385SBrandon 
DestroyHashMap(PetscCtxRt p)32712a8381b2SBarry Smith static PetscErrorCode DestroyHashMap(PetscCtxRt p)
32725552b385SBrandon {
32735552b385SBrandon   PetscFunctionBegin;
32745552b385SBrandon   PetscCall(PetscHMapIDestroy((PetscHMapI *)p));
32755552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
32765552b385SBrandon }
32775552b385SBrandon #endif
32785552b385SBrandon 
32795552b385SBrandon /*@C
32805552b385SBrandon   DMPlexGeomDataAndGrads - Exposes Control Points and Control Point Weights defining the underlying geometry allowing user manipulation of the geometry.
32815552b385SBrandon 
32825552b385SBrandon   Collective
32835552b385SBrandon 
32845552b385SBrandon   Input Parameters:
32855552b385SBrandon + dm           - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
32865552b385SBrandon - fullGeomGrad - PetscBool flag. Determines how the Surface Area and Volume Gradients wrt to Control Points and Control Point Weights are calculated.
32875552b385SBrandon                       PETSC_FALSE :: Surface Area Gradient wrt Control Points and Control Point Weights are calculated using the change in the local
32885552b385SBrandon                                      FACE changes (not the entire body). Volume Gradients are not calculated. Faster computations.
32895552b385SBrandon                       PETSC_TRUE  :: Surface Area Gradietn wrt to Control Points and Control Point Weights are calculated using the change observed in
32905552b385SBrandon                                      the entire solid body. Volume Gradients are calculated. Slower computation due to the need to generate a new solid
32915552b385SBrandon                                      body geometry for every Control Point and Control Point Weight change.
32925552b385SBrandon 
32935552b385SBrandon   Output Parameter:
32945552b385SBrandon . dm - The updated DM object representing the mesh with PetscContainers containing the Control Point, Control Point Weight and Gradient Data.
32955552b385SBrandon 
32965552b385SBrandon   Level: intermediate
32975552b385SBrandon 
32985552b385SBrandon   Note:
32995552b385SBrandon   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).
33005552b385SBrandon 
33015552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexModifyEGADSGeomModel()`
33025552b385SBrandon @*/
DMPlexGeomDataAndGrads(DM dm,PetscBool fullGeomGrad)3303ce78bad3SBarry Smith PetscErrorCode DMPlexGeomDataAndGrads(DM dm, PetscBool fullGeomGrad) PeNS
33045552b385SBrandon {
33055552b385SBrandon #if defined(PETSC_HAVE_EGADS)
33065552b385SBrandon   /* PETSc Variables */
33075552b385SBrandon   PetscContainer modelObj;
33085552b385SBrandon   PetscHMapI     faceCntrlPtRow_Start = NULL, faceCPWeightsRow_Start = NULL;
33095552b385SBrandon   PetscHMapI     pointSurfGradRow_Start = NULL;
33105552b385SBrandon   Mat            pointSurfGrad, cpEquiv;
33115552b385SBrandon   IS             faceLabelValues, edgeLabelValues, vertexLabelValues;
33125552b385SBrandon   PetscInt       faceLabelSize, edgeLabelSize, vertexLabelSize;
33135552b385SBrandon   PetscBool      islite = PETSC_FALSE;
33145552b385SBrandon   /* EGADS Variables */
33155552b385SBrandon   ego model, geom, *bodies, *fobjs = NULL;
33165552b385SBrandon   int oclass, mtype, *senses;
33175552b385SBrandon   int Nb, Nf;
33185552b385SBrandon #endif
33195552b385SBrandon 
33205552b385SBrandon   PetscFunctionBegin;
33215552b385SBrandon #if defined(PETSC_HAVE_EGADS)
33225552b385SBrandon 
33235552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
33245552b385SBrandon   if (!modelObj) {
33255552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
33265552b385SBrandon     PetscCheck(modelObj, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input DM must have attached EGADS Geometry Model");
33275552b385SBrandon     islite = PETSC_TRUE;
33285552b385SBrandon     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");
33295552b385SBrandon   }
33305552b385SBrandon 
33315552b385SBrandon   // Get attached EGADS model (pointer)
33322a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
33335552b385SBrandon 
33345552b385SBrandon   // Get the bodies in the model
33355552b385SBrandon   if (islite) {
33365552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
33375552b385SBrandon   } else {
33385552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
33395552b385SBrandon   }
33405552b385SBrandon 
33415552b385SBrandon   ego body = bodies[0]; // Only operate on 1st body. Model should only have 1 body.
33425552b385SBrandon 
33435552b385SBrandon   // Get the total number of FACEs in the model
33445552b385SBrandon   if (islite) {
33455552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
33465552b385SBrandon   } else {
33475552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
33485552b385SBrandon   }
33495552b385SBrandon 
33505552b385SBrandon   // Get the total number of points and IDs in the DMPlex with a "EGADS Face Label"
33515552b385SBrandon   // This will provide the total number of DMPlex points on the boundary of the geometry
33525552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Face ID", &faceLabelValues));
33535552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Face ID", &faceLabelSize));
33545552b385SBrandon 
33555552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Edge ID", &edgeLabelValues));
33565552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Edge ID", &edgeLabelSize));
33575552b385SBrandon 
33585552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Vertex ID", &vertexLabelValues));
33595552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Vertex ID", &vertexLabelSize));
33605552b385SBrandon 
33615552b385SBrandon   const PetscInt *faceIndices, *edgeIndices, *vertexIndices;
33625552b385SBrandon   PetscCall(ISGetIndices(faceLabelValues, &faceIndices));
33635552b385SBrandon   PetscCall(ISGetIndices(edgeLabelValues, &edgeIndices));
33645552b385SBrandon   PetscCall(ISGetIndices(vertexLabelValues, &vertexIndices));
33655552b385SBrandon 
33665552b385SBrandon   // Get the points associated with each FACE, EDGE and VERTEX label in the DM
33675552b385SBrandon   PetscInt totalNumPoints = 0;
33685552b385SBrandon   for (int f = 0; f < faceLabelSize; ++f) {
33695552b385SBrandon     // Cycle through FACE labels
33705552b385SBrandon     PetscInt size;
33715552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Face ID", faceIndices[f], &size));
33725552b385SBrandon     totalNumPoints += size;
33735552b385SBrandon   }
33745552b385SBrandon   PetscCall(ISRestoreIndices(faceLabelValues, &faceIndices));
33755552b385SBrandon   PetscCall(ISDestroy(&faceLabelValues));
33765552b385SBrandon 
33775552b385SBrandon   for (int e = 0; e < edgeLabelSize; ++e) {
33785552b385SBrandon     // Cycle Through EDGE Labels
33795552b385SBrandon     PetscInt size;
33805552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Edge ID", edgeIndices[e], &size));
33815552b385SBrandon     totalNumPoints += size;
33825552b385SBrandon   }
33835552b385SBrandon   PetscCall(ISRestoreIndices(edgeLabelValues, &edgeIndices));
33845552b385SBrandon   PetscCall(ISDestroy(&edgeLabelValues));
33855552b385SBrandon 
33865552b385SBrandon   for (int ii = 0; ii < vertexLabelSize; ++ii) {
33875552b385SBrandon     // Cycle Through VERTEX Labels
33885552b385SBrandon     PetscInt size;
33895552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Vertex ID", vertexIndices[ii], &size));
33905552b385SBrandon     totalNumPoints += size;
33915552b385SBrandon   }
33925552b385SBrandon   PetscCall(ISRestoreIndices(vertexLabelValues, &vertexIndices));
33935552b385SBrandon   PetscCall(ISDestroy(&vertexLabelValues));
33945552b385SBrandon 
33955552b385SBrandon   int     maxNumCPs   = 0;
33965552b385SBrandon   int     totalNumCPs = 0;
33975552b385SBrandon   ego     bRef, bPrev, bNext, fgeom, *lobjs;
33985552b385SBrandon   int     id, boclass, bmtype, *bpinfo;
33995552b385SBrandon   int     foclass, fmtype, Nl, *lsenses;
34005552b385SBrandon   double *bprv;
34015552b385SBrandon   double  fdata[4];
34025552b385SBrandon 
34035552b385SBrandon   // Create Hash Tables
34045552b385SBrandon   PetscInt cntr = 0, wcntr = 0, vcntr = 0;
34055552b385SBrandon   PetscCall(PetscHMapICreate(&faceCntrlPtRow_Start));
34065552b385SBrandon   PetscCall(PetscHMapICreate(&faceCPWeightsRow_Start));
34075552b385SBrandon 
34085552b385SBrandon   for (int f = 0; f < Nf; ++f) {
34095552b385SBrandon     // Need to get the maximum number of Control Points defining the FACEs
34105552b385SBrandon     ego face = fobjs[f];
34115552b385SBrandon     int maxNumCPs_temp;
34125552b385SBrandon 
34135552b385SBrandon     if (islite) {
34145552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
34155552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34165552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34175552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34185552b385SBrandon     } else {
34195552b385SBrandon       id = EG_indexBodyTopo(body, face);
34205552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34215552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34225552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34235552b385SBrandon     }
34245552b385SBrandon     maxNumCPs_temp = bpinfo[2] * bpinfo[5];
34255552b385SBrandon     totalNumCPs += bpinfo[2] * bpinfo[5];
34265552b385SBrandon 
3427ac530a7eSPierre Jolivet     if (maxNumCPs_temp > maxNumCPs) maxNumCPs = maxNumCPs_temp;
34285552b385SBrandon   }
34295552b385SBrandon 
34305552b385SBrandon   PetscInt *cpCoordDataLengthPtr, *wDataLengthPtr;
34315552b385SBrandon   PetscInt  cpCoordDataLength = 3 * totalNumCPs;
34325552b385SBrandon   PetscInt  wDataLength       = totalNumCPs;
34335552b385SBrandon   cpCoordDataLengthPtr        = &cpCoordDataLength;
34345552b385SBrandon   wDataLengthPtr              = &wDataLength;
34355552b385SBrandon 
34365552b385SBrandon   Vec          cntrlPtCoordsVec, cntrlPtWeightsVec;
34375552b385SBrandon   PetscScalar *cntrlPtCoords, *cntrlPtWeights;
34385552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &cntrlPtCoordsVec));
34395552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &cntrlPtWeightsVec));
34405552b385SBrandon 
34415552b385SBrandon   // For dSA/dCPi
34425552b385SBrandon   Vec          gradSACPVec, gradSAWVec, gradVCPVec, gradVWVec;
34435552b385SBrandon   PetscScalar *gradSACP, *gradSAW, *gradVCP, *gradVW;
34445552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &gradSACPVec));
34455552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &gradSAWVec));
34465552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &gradVCPVec));
34475552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &gradVWVec));
34485552b385SBrandon 
34495552b385SBrandon   // Control Point - Vertex/Edge/Face Relationship
34505552b385SBrandon   PetscInt *cp_vertex, *cp_edge, *cp_face;
34515552b385SBrandon   PetscInt *w_vertex, *w_edge, *w_face;
34525552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_vertex));
34535552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_edge));
34545552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_face));
34555552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_vertex));
34565552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_edge));
34575552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_face));
34585552b385SBrandon 
34595552b385SBrandon   for (int f = 0; f < Nf; ++f) {
34605552b385SBrandon     // Need to Populate Control Point Coordinates and Weight Vectors
34615552b385SBrandon     ego           face = fobjs[f];
34625552b385SBrandon     ego          *vobjs, *eobjs;
34635552b385SBrandon     int           offsetCoord, offsetWeight;
34645552b385SBrandon     PetscInt      Nv, Ne, wRowStart = 0;
34655552b385SBrandon     PetscHashIter hashKeyIter, wHashKeyIter;
34665552b385SBrandon     PetscBool     hashKeyFound, wHashKeyFound;
34675552b385SBrandon 
34685552b385SBrandon     if (islite) {
34695552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
34705552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34715552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34725552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34735552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (body, face, NODE, &Nv, &vobjs));
34745552b385SBrandon     } else {
34755552b385SBrandon       id = EG_indexBodyTopo(body, face);
34765552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34775552b385SBrandon       PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34785552b385SBrandon       PetscCallEGADS(EG_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34795552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (body, face, NODE, &Nv, &vobjs));
34805552b385SBrandon     }
34815552b385SBrandon 
34825552b385SBrandon     // Store Face ID to 1st Row of Control Point Vector
34835552b385SBrandon     PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, id, &hashKeyIter, &hashKeyFound));
34845552b385SBrandon 
34855552b385SBrandon     if (!hashKeyFound) PetscCall(PetscHMapISet(faceCntrlPtRow_Start, id, cntr));
34865552b385SBrandon 
34875552b385SBrandon     PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, &cntrlPtCoords));
34885552b385SBrandon     offsetCoord = bpinfo[3] + bpinfo[6];
34895552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; ++jj) {
34905552b385SBrandon       cntrlPtCoords[cntr] = bprv[offsetCoord + jj];
34915552b385SBrandon       cntr += 1;
34925552b385SBrandon     }
34935552b385SBrandon 
34945552b385SBrandon     // Store Face ID to 1st Row of Control Point Weight Vector
34955552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, id, &wHashKeyIter, &wHashKeyFound));
34965552b385SBrandon 
34975552b385SBrandon     if (!wHashKeyFound) {
34985552b385SBrandon       PetscCall(PetscHMapISet(faceCPWeightsRow_Start, id, wcntr));
34995552b385SBrandon       wRowStart = wcntr;
35005552b385SBrandon     }
35015552b385SBrandon 
35025552b385SBrandon     PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, &cntrlPtWeights));
35035552b385SBrandon     offsetWeight = bpinfo[3] + bpinfo[6] + (3 * bpinfo[2] * bpinfo[5]);
35045552b385SBrandon     for (int jj = 0; jj < bpinfo[2] * bpinfo[5]; ++jj) {
35055552b385SBrandon       cntrlPtWeights[wcntr] = bprv[offsetWeight + jj];
35065552b385SBrandon       cp_face[wcntr]        = id;
35075552b385SBrandon       w_face[wcntr]         = id;
35085552b385SBrandon       wcntr += 1;
35095552b385SBrandon     }
35105552b385SBrandon     PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, &cntrlPtWeights));
35115552b385SBrandon 
3512bfe80ac4SPierre Jolivet     // Associate Control Points with Vertex IDs
35135552b385SBrandon     PetscScalar xcp, ycp, zcp;
35145552b385SBrandon     offsetCoord = bpinfo[3] + bpinfo[6];
35155552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; jj += 3) {
35165552b385SBrandon       xcp = bprv[offsetCoord + jj + 0];
35175552b385SBrandon       ycp = bprv[offsetCoord + jj + 1];
35185552b385SBrandon       zcp = bprv[offsetCoord + jj + 2];
35195552b385SBrandon 
35205552b385SBrandon       //Initialize Control Point and Weight to Vertex ID relationship to -1
35215552b385SBrandon       cp_vertex[vcntr] = -1;
35225552b385SBrandon       w_vertex[vcntr]  = -1;
35235552b385SBrandon       cp_edge[vcntr]   = -1;
35245552b385SBrandon       w_edge[vcntr]    = -1;
35255552b385SBrandon 
35265552b385SBrandon       for (int kk = 0; kk < Nv; ++kk) {
35275552b385SBrandon         int         vid;
35285552b385SBrandon         double      vCoords[3];
35295552b385SBrandon         PetscScalar vDelta;
35305552b385SBrandon         ego         vertex = vobjs[kk];
35315552b385SBrandon 
35325552b385SBrandon         if (islite) {
35335552b385SBrandon           vid = EGlite_indexBodyTopo(body, vertex);
35345552b385SBrandon           PetscCallEGADS(EGlite_evaluate, (vertex, NULL, vCoords));
35355552b385SBrandon         } else {
35365552b385SBrandon           vid = EG_indexBodyTopo(body, vertex);
35375552b385SBrandon           PetscCallEGADS(EG_evaluate, (vertex, NULL, vCoords));
35385552b385SBrandon         }
35395552b385SBrandon         vDelta = PetscSqrtReal(PetscSqr(vCoords[0] - xcp) + PetscSqr(vCoords[1] - ycp) + PetscSqr(vCoords[2] - zcp));
35405552b385SBrandon 
35415552b385SBrandon         if (vDelta < 1.0E-15) {
35425552b385SBrandon           cp_vertex[vcntr] = vid;
35435552b385SBrandon           w_vertex[vcntr]  = vid;
35445552b385SBrandon         }
35455552b385SBrandon       }
35465552b385SBrandon       vcntr += 1;
35475552b385SBrandon     }
35485552b385SBrandon     // These two line could be replaced with DMPlexFreeGeomObject()
35495552b385SBrandon     if (islite) EGlite_free(vobjs);
35505552b385SBrandon     else EG_free(vobjs);
35515552b385SBrandon 
35525552b385SBrandon     // Associate Control Points with Edge IDs
35535552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, face, EDGE, &Ne, &eobjs));
35545552b385SBrandon     else PetscCallEGADS(EG_getBodyTopos, (body, face, EDGE, &Ne, &eobjs));
35555552b385SBrandon 
35565552b385SBrandon     int cpV1, cpV2;
35575552b385SBrandon     int minID, maxID;
35585552b385SBrandon 
35595552b385SBrandon     // Along vmin axis
35605552b385SBrandon     minID = wRowStart;
35615552b385SBrandon     maxID = wRowStart + (bpinfo[2] - 1);
35625552b385SBrandon     cpV1  = cp_vertex[minID];
35635552b385SBrandon     cpV2  = cp_vertex[maxID];
35645552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
35655552b385SBrandon       ego edge = eobjs[jj];
35665552b385SBrandon       ego egeom, *nobjs;
35675552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
35685552b385SBrandon       int n1ID, n2ID, eid;
35695552b385SBrandon 
35705552b385SBrandon       if (islite) {
35715552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
35725552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
35735552b385SBrandon       } else {
35745552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
35755552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
35765552b385SBrandon       }
35775552b385SBrandon 
35785552b385SBrandon       if (emtype != DEGENERATE) {
35795552b385SBrandon         // Get IDs for current Edge's End Vertices
35805552b385SBrandon         if (islite) {
35815552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
35825552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
35835552b385SBrandon         } else {
35845552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
35855552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
35865552b385SBrandon         }
35875552b385SBrandon 
35885552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
35895552b385SBrandon           for (int kk = minID + 1; kk < maxID; ++kk) {
35905552b385SBrandon             cp_edge[kk] = eid;
35915552b385SBrandon             w_edge[kk]  = eid;
35925552b385SBrandon           }
35935552b385SBrandon         }
35945552b385SBrandon       }
35955552b385SBrandon     }
35965552b385SBrandon 
35975552b385SBrandon     // Along vmax axis
35985552b385SBrandon     minID = wRowStart + (bpinfo[2] * (bpinfo[5] - 1));
35995552b385SBrandon     maxID = wRowStart + (bpinfo[2] * bpinfo[5] - 1);
36005552b385SBrandon 
36015552b385SBrandon     cpV1 = cp_vertex[minID];
36025552b385SBrandon     cpV2 = cp_vertex[maxID];
36035552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
36045552b385SBrandon       ego edge = eobjs[jj];
36055552b385SBrandon       ego egeom, *nobjs;
36065552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
36075552b385SBrandon       int n1ID, n2ID, eid;
36085552b385SBrandon 
36095552b385SBrandon       if (islite) {
36105552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
36115552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36125552b385SBrandon       } else {
36135552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
36145552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36155552b385SBrandon       }
36165552b385SBrandon 
36175552b385SBrandon       if (emtype != DEGENERATE) {
36185552b385SBrandon         // Get IDs for current Edge's End Vertices
36195552b385SBrandon         if (islite) {
36205552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
36215552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
36225552b385SBrandon         } else {
36235552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
36245552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
36255552b385SBrandon         }
36265552b385SBrandon 
36275552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
36285552b385SBrandon           for (int kk = minID + 1; kk < maxID - 1; ++kk) {
36295552b385SBrandon             cp_edge[kk] = eid;
36305552b385SBrandon             w_edge[kk]  = eid;
36315552b385SBrandon           }
36325552b385SBrandon         }
36335552b385SBrandon       }
36345552b385SBrandon     }
36355552b385SBrandon 
36365552b385SBrandon     // Along umin axis
36375552b385SBrandon     minID = wRowStart;
36385552b385SBrandon     maxID = wRowStart + (bpinfo[2] * (bpinfo[5] - 1));
36395552b385SBrandon 
36405552b385SBrandon     cpV1 = cp_vertex[minID];
36415552b385SBrandon     cpV2 = cp_vertex[maxID];
36425552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
36435552b385SBrandon       ego edge = eobjs[jj];
36445552b385SBrandon       ego egeom, *nobjs;
36455552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
36465552b385SBrandon       int n1ID, n2ID, eid;
36475552b385SBrandon 
36485552b385SBrandon       if (islite) {
36495552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
36505552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36515552b385SBrandon       } else {
36525552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
36535552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36545552b385SBrandon       }
36555552b385SBrandon 
36565552b385SBrandon       if (emtype != DEGENERATE) {
36575552b385SBrandon         // Get IDs for current Edge's End Vertices
36585552b385SBrandon         if (islite) {
36595552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
36605552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
36615552b385SBrandon         } else {
36625552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
36635552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
36645552b385SBrandon         }
36655552b385SBrandon 
36665552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
36675552b385SBrandon           for (int kk = minID + bpinfo[2]; kk < maxID; kk += bpinfo[2]) {
36685552b385SBrandon             cp_edge[kk] = eid;
36695552b385SBrandon             w_edge[kk]  = eid;
36705552b385SBrandon           }
36715552b385SBrandon         }
36725552b385SBrandon       }
36735552b385SBrandon     }
36745552b385SBrandon 
36755552b385SBrandon     // Along umax axis
36765552b385SBrandon     minID = wRowStart + (bpinfo[2] - 1);
36775552b385SBrandon     maxID = wRowStart + (bpinfo[2] * bpinfo[5]) - 1;
36785552b385SBrandon     cpV1  = cp_vertex[minID];
36795552b385SBrandon     cpV2  = cp_vertex[maxID];
36805552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
36815552b385SBrandon       ego edge = eobjs[jj];
36825552b385SBrandon       ego egeom, *nobjs;
36835552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
36845552b385SBrandon       int n1ID, n2ID, eid;
36855552b385SBrandon 
36865552b385SBrandon       if (islite) {
36875552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
36885552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36895552b385SBrandon       } else {
36905552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
36915552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36925552b385SBrandon       }
36935552b385SBrandon 
36945552b385SBrandon       if (emtype != DEGENERATE) {
36955552b385SBrandon         // Get IDs for current Edge's End Vertices
36965552b385SBrandon         if (islite) {
36975552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
36985552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
36995552b385SBrandon         } else {
37005552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
37015552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
37025552b385SBrandon         }
37035552b385SBrandon 
37045552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
37055552b385SBrandon           for (int kk = minID + bpinfo[2]; kk < maxID; kk += bpinfo[2]) {
37065552b385SBrandon             cp_edge[kk] = eid;
37075552b385SBrandon             w_edge[kk]  = eid;
37085552b385SBrandon           }
37095552b385SBrandon         }
37105552b385SBrandon       }
37115552b385SBrandon     }
37125552b385SBrandon     // These two lines could be replaced with DMPlexFreeGeomObject()
37135552b385SBrandon     if (islite) EGlite_free(eobjs);
37145552b385SBrandon     else EG_free(eobjs);
37155552b385SBrandon   }
37165552b385SBrandon 
3717bfe80ac4SPierre Jolivet   // Determine Control Point Equivalence Matrix relating Control Points between Surfaces
37185552b385SBrandon   //     Note: The Weights will also be tied together in the same manner
37195552b385SBrandon   //           Also can use the Weight Hash Table for Row Start ID of each Face
37205552b385SBrandon   const PetscInt cpRowSize = totalNumCPs;
37215552b385SBrandon   const PetscInt cpColSize = cpRowSize;
37225552b385SBrandon   PetscInt      *maxNumRelatePtr;
37235552b385SBrandon   PetscInt       maxNumRelate = 0;
37245552b385SBrandon 
37255552b385SBrandon   // Create Point Surface Gradient Matrix
37265552b385SBrandon   PetscCall(MatCreate(PETSC_COMM_WORLD, &cpEquiv));
37275552b385SBrandon   PetscCall(MatSetSizes(cpEquiv, PETSC_DECIDE, PETSC_DECIDE, cpRowSize, cpColSize));
37285552b385SBrandon   PetscCall(MatSetType(cpEquiv, MATAIJ));
37295552b385SBrandon   PetscCall(MatSetUp(cpEquiv));
37305552b385SBrandon 
37315552b385SBrandon   for (int ii = 0; ii < totalNumCPs; ++ii) {
37325552b385SBrandon     PetscScalar x1, y1, z1;
37335552b385SBrandon     PetscInt    maxRelateTemp = 0;
37345552b385SBrandon 
37355552b385SBrandon     x1 = cntrlPtCoords[(3 * ii) + 0];
37365552b385SBrandon     y1 = cntrlPtCoords[(3 * ii) + 1];
37375552b385SBrandon     z1 = cntrlPtCoords[(3 * ii) + 2];
37385552b385SBrandon 
37395552b385SBrandon     for (int jj = 0; jj < totalNumCPs; ++jj) {
37405552b385SBrandon       PetscScalar x2, y2, z2;
37415552b385SBrandon       PetscScalar cpDelta, eqFactor;
37425552b385SBrandon       x2 = cntrlPtCoords[(3 * jj) + 0];
37435552b385SBrandon       y2 = cntrlPtCoords[(3 * jj) + 1];
37445552b385SBrandon       z2 = cntrlPtCoords[(3 * jj) + 2];
37455552b385SBrandon 
37465552b385SBrandon       cpDelta = PetscSqrtReal(PetscSqr(x2 - x1) + PetscSqr(y2 - y1) + PetscSqr(z2 - z1));
37475552b385SBrandon       if (cpDelta < 1.0E-15) {
37485552b385SBrandon         eqFactor = 1.0;
37495552b385SBrandon         maxRelateTemp += 1;
37505552b385SBrandon       } else {
37515552b385SBrandon         eqFactor = 0.0;
37525552b385SBrandon       }
37535552b385SBrandon 
3754f0b74427SPierre Jolivet       // Store Results in PETSc Mat
37555552b385SBrandon       PetscCall(MatSetValue(cpEquiv, ii, jj, eqFactor, INSERT_VALUES));
37565552b385SBrandon     }
37575552b385SBrandon     if (maxRelateTemp > maxNumRelate) maxNumRelate = maxRelateTemp;
37585552b385SBrandon   }
37595552b385SBrandon   maxNumRelatePtr = &maxNumRelate;
37605552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, &cntrlPtCoords));
37615552b385SBrandon 
37625552b385SBrandon   // Assemble Point Surface Grad Matrix
37635552b385SBrandon   PetscCall(MatAssemblyBegin(cpEquiv, MAT_FINAL_ASSEMBLY));
37645552b385SBrandon   PetscCall(MatAssemblyEnd(cpEquiv, MAT_FINAL_ASSEMBLY));
37655552b385SBrandon 
37665552b385SBrandon   // Attach Control Point and Weight Data to DM
37675552b385SBrandon   {
37685552b385SBrandon     PetscContainer cpOrgObj, cpCoordLengthObj;
37695552b385SBrandon     PetscContainer wOrgObj, wDataLengthObj;
37705552b385SBrandon     PetscContainer cp_faceObj, cp_edgeObj, cp_vertexObj;
37715552b385SBrandon     PetscContainer w_faceObj, w_edgeObj, w_vertexObj;
37725552b385SBrandon     PetscContainer maxNumRelateObj;
37735552b385SBrandon 
37745552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpOrgObj));
37755552b385SBrandon     if (!cpOrgObj) {
37765552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpOrgObj));
37775552b385SBrandon       PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
37785552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Hash Table", (PetscObject)cpOrgObj));
37795552b385SBrandon       PetscCall(PetscContainerDestroy(&cpOrgObj));
37805552b385SBrandon     } else {
37815552b385SBrandon       PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
37825552b385SBrandon     }
37835552b385SBrandon 
37845552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinates", (PetscObject)cntrlPtCoordsVec));
37855552b385SBrandon     PetscCall(VecDestroy(&cntrlPtCoordsVec));
37865552b385SBrandon 
37875552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordLengthObj));
37885552b385SBrandon     if (!cpCoordLengthObj) {
37895552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordLengthObj));
37905552b385SBrandon       PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
37915552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject)cpCoordLengthObj));
37925552b385SBrandon       PetscCall(PetscContainerDestroy(&cpCoordLengthObj));
37935552b385SBrandon     } else {
37945552b385SBrandon       PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
37955552b385SBrandon     }
37965552b385SBrandon 
37975552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wOrgObj));
37985552b385SBrandon     if (!wOrgObj) {
37995552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wOrgObj));
38005552b385SBrandon       PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
38015552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject)wOrgObj));
38025552b385SBrandon       PetscCall(PetscContainerDestroy(&wOrgObj));
38035552b385SBrandon     } else {
38045552b385SBrandon       PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
38055552b385SBrandon     }
38065552b385SBrandon 
38075552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data", (PetscObject)cntrlPtWeightsVec));
38085552b385SBrandon     PetscCall(VecDestroy(&cntrlPtWeightsVec));
38095552b385SBrandon 
38105552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
38115552b385SBrandon     if (!wDataLengthObj) {
38125552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wDataLengthObj));
38135552b385SBrandon       PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
38145552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data Length", (PetscObject)wDataLengthObj));
38155552b385SBrandon       PetscCall(PetscContainerDestroy(&wDataLengthObj));
38165552b385SBrandon     } else {
38175552b385SBrandon       PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
38185552b385SBrandon     }
38195552b385SBrandon 
3820bfe80ac4SPierre Jolivet     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Equivalency Matrix", (PetscObject)cpEquiv));
38215552b385SBrandon 
38225552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject *)&maxNumRelateObj));
38235552b385SBrandon     if (!maxNumRelateObj) {
38245552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &maxNumRelateObj));
38255552b385SBrandon       PetscCall(PetscContainerSetPointer(maxNumRelateObj, maxNumRelatePtr));
38265552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject)maxNumRelateObj));
38275552b385SBrandon       PetscCall(PetscContainerDestroy(&maxNumRelateObj));
38285552b385SBrandon     } else {
38295552b385SBrandon       PetscCall(PetscContainerSetPointer(maxNumRelateObj, maxNumRelatePtr));
38305552b385SBrandon     }
38315552b385SBrandon 
38325552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Face Map", (PetscObject *)&cp_faceObj));
38335552b385SBrandon     if (!cp_faceObj) {
38345552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_faceObj));
38355552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_faceObj, cp_face));
38365552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_faceObj, PetscCtxDestroyDefault));
38375552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Face Map", (PetscObject)cp_faceObj));
38385552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_faceObj));
38395552b385SBrandon     } else {
38405552b385SBrandon       void *tmp;
38415552b385SBrandon 
38425552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_faceObj, &tmp));
38435552b385SBrandon       PetscCall(PetscFree(tmp));
38445552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_faceObj, cp_face));
38455552b385SBrandon     }
38465552b385SBrandon 
38475552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject *)&w_faceObj));
38485552b385SBrandon     if (!w_faceObj) {
38495552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_faceObj));
38505552b385SBrandon       PetscCall(PetscContainerSetPointer(w_faceObj, w_face));
38515552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_faceObj, PetscCtxDestroyDefault));
38525552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject)w_faceObj));
38535552b385SBrandon       PetscCall(PetscContainerDestroy(&w_faceObj));
38545552b385SBrandon     } else {
38555552b385SBrandon       void *tmp;
38565552b385SBrandon 
38575552b385SBrandon       PetscCall(PetscContainerGetPointer(w_faceObj, &tmp));
38585552b385SBrandon       PetscCall(PetscFree(tmp));
38595552b385SBrandon       PetscCall(PetscContainerSetPointer(w_faceObj, w_face));
38605552b385SBrandon     }
38615552b385SBrandon 
38625552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Edge Map", (PetscObject *)&cp_edgeObj));
38635552b385SBrandon     if (!cp_edgeObj) {
38645552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_edgeObj));
38655552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_edgeObj, cp_edge));
38665552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_edgeObj, PetscCtxDestroyDefault));
38675552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Edge Map", (PetscObject)cp_edgeObj));
38685552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_edgeObj));
38695552b385SBrandon     } else {
38705552b385SBrandon       void *tmp;
38715552b385SBrandon 
38725552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_edgeObj, &tmp));
38735552b385SBrandon       PetscCall(PetscFree(tmp));
38745552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_edgeObj, cp_edge));
38755552b385SBrandon     }
38765552b385SBrandon 
38775552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject *)&w_edgeObj));
38785552b385SBrandon     if (!w_edgeObj) {
38795552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_edgeObj));
38805552b385SBrandon       PetscCall(PetscContainerSetPointer(w_edgeObj, w_edge));
38815552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_edgeObj, PetscCtxDestroyDefault));
38825552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject)w_edgeObj));
38835552b385SBrandon       PetscCall(PetscContainerDestroy(&w_edgeObj));
38845552b385SBrandon     } else {
38855552b385SBrandon       void *tmp;
38865552b385SBrandon 
38875552b385SBrandon       PetscCall(PetscContainerGetPointer(w_edgeObj, &tmp));
38885552b385SBrandon       PetscCall(PetscFree(tmp));
38895552b385SBrandon       PetscCall(PetscContainerSetPointer(w_edgeObj, w_edge));
38905552b385SBrandon     }
38915552b385SBrandon 
38925552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Vertex Map", (PetscObject *)&cp_vertexObj));
38935552b385SBrandon     if (!cp_vertexObj) {
38945552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_vertexObj));
38955552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_vertexObj, cp_vertex));
38965552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_vertexObj, PetscCtxDestroyDefault));
38975552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Vertex Map", (PetscObject)cp_vertexObj));
38985552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_vertexObj));
38995552b385SBrandon     } else {
39005552b385SBrandon       void *tmp;
39015552b385SBrandon 
39025552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_vertexObj, &tmp));
39035552b385SBrandon       PetscCall(PetscFree(tmp));
39045552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_vertexObj, cp_vertex));
39055552b385SBrandon     }
39065552b385SBrandon 
39075552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject *)&w_vertexObj));
39085552b385SBrandon     if (!w_vertexObj) {
39095552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_vertexObj));
39105552b385SBrandon       PetscCall(PetscContainerSetPointer(w_vertexObj, w_vertex));
39115552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_vertexObj, PetscCtxDestroyDefault));
39125552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject)w_vertexObj));
39135552b385SBrandon       PetscCall(PetscContainerDestroy(&w_vertexObj));
39145552b385SBrandon     } else {
39155552b385SBrandon       void *tmp;
39165552b385SBrandon 
39175552b385SBrandon       PetscCall(PetscContainerGetPointer(w_vertexObj, &tmp));
39185552b385SBrandon       PetscCall(PetscFree(tmp));
39195552b385SBrandon       PetscCall(PetscContainerSetPointer(w_vertexObj, w_vertex));
39205552b385SBrandon     }
39215552b385SBrandon   }
39225552b385SBrandon 
39235552b385SBrandon   // Define Matrix to store  Geometry Gradient information dGeom_i/dCPj_i
39245552b385SBrandon   PetscInt       gcntr   = 0;
39255552b385SBrandon   const PetscInt rowSize = 3 * maxNumCPs * totalNumPoints;
39265552b385SBrandon   const PetscInt colSize = 4 * Nf;
39275552b385SBrandon 
39285552b385SBrandon   // Create Point Surface Gradient Matrix
39295552b385SBrandon   PetscCall(MatCreate(PETSC_COMM_WORLD, &pointSurfGrad));
39305552b385SBrandon   PetscCall(MatSetSizes(pointSurfGrad, PETSC_DECIDE, PETSC_DECIDE, rowSize, colSize));
39315552b385SBrandon   PetscCall(MatSetType(pointSurfGrad, MATAIJ));
39325552b385SBrandon   PetscCall(MatSetUp(pointSurfGrad));
39335552b385SBrandon 
39345552b385SBrandon   // Create Hash Table to store Point's stare row in surfaceGrad[][]
39355552b385SBrandon   PetscCall(PetscHMapICreate(&pointSurfGradRow_Start));
39365552b385SBrandon 
39375552b385SBrandon   // Get Coordinates for the DMPlex point
39385552b385SBrandon   DM           cdm;
39395552b385SBrandon   PetscInt     dE, Nv;
39405552b385SBrandon   Vec          coordinatesLocal;
39415552b385SBrandon   PetscScalar *coords = NULL;
39425552b385SBrandon 
39435552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
39445552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &dE));
39455552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
39465552b385SBrandon 
39475552b385SBrandon   // CYCLE THROUGH FACEs
39485552b385SBrandon   PetscScalar maxGrad = 0.;
39495552b385SBrandon   PetscCall(VecGetArrayWrite(gradSACPVec, &gradSACP));
39505552b385SBrandon   PetscCall(VecGetArrayWrite(gradSAWVec, &gradSAW));
39515552b385SBrandon   PetscCall(VecGetArrayWrite(gradVCPVec, &gradVCP));
39525552b385SBrandon   PetscCall(VecGetArrayWrite(gradVWVec, &gradVW));
39535552b385SBrandon   for (int f = 0; f < Nf; ++f) {
39545552b385SBrandon     ego             face = fobjs[f];
39555552b385SBrandon     ego            *eobjs, *nobjs;
39565552b385SBrandon     PetscInt        fid, Ne, Nn;
39575552b385SBrandon     DMLabel         faceLabel, edgeLabel, nodeLabel;
39585552b385SBrandon     PetscHMapI      currFaceUniquePoints = NULL;
39595552b385SBrandon     IS              facePoints, edgePoints, nodePoints;
39605552b385SBrandon     const PetscInt *fIndices, *eIndices, *nIndices;
39615552b385SBrandon     PetscInt        fSize, eSize, nSize;
39625552b385SBrandon     PetscHashIter   fHashKeyIter, eHashKeyIter, nHashKeyIter, pHashKeyIter;
39635552b385SBrandon     PetscBool       fHashKeyFound, eHashKeyFound, nHashKeyFound, pHashKeyFound;
39645552b385SBrandon     PetscInt        cfCntr = 0;
39655552b385SBrandon 
39665552b385SBrandon     // Get Geometry Object for the Current FACE
39675552b385SBrandon     if (islite) {
39685552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
39695552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
39705552b385SBrandon     } else {
39715552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
39725552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
39735552b385SBrandon     }
39745552b385SBrandon 
39755552b385SBrandon     // Get all EDGE and NODE objects attached to the current FACE
39765552b385SBrandon     if (islite) {
39775552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
39785552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, NODE, &Nn, &nobjs));
39795552b385SBrandon     } else {
39805552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
39815552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, NODE, &Nn, &nobjs));
39825552b385SBrandon     }
39835552b385SBrandon 
39845552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Face ID" and store them in a Hash Table for later use
39855552b385SBrandon     if (islite) {
39865552b385SBrandon       fid = EGlite_indexBodyTopo(body, face);
39875552b385SBrandon     } else {
39885552b385SBrandon       fid = EG_indexBodyTopo(body, face);
39895552b385SBrandon     }
39905552b385SBrandon 
39915552b385SBrandon     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
39925552b385SBrandon     PetscCall(DMLabelGetStratumIS(faceLabel, fid, &facePoints));
39935552b385SBrandon     PetscCall(ISGetIndices(facePoints, &fIndices));
39945552b385SBrandon     PetscCall(ISGetSize(facePoints, &fSize));
39955552b385SBrandon 
39965552b385SBrandon     PetscCall(PetscHMapICreate(&currFaceUniquePoints));
39975552b385SBrandon 
39985552b385SBrandon     for (int jj = 0; jj < fSize; ++jj) {
39995552b385SBrandon       PetscCall(PetscHMapIFind(currFaceUniquePoints, fIndices[jj], &fHashKeyIter, &fHashKeyFound));
40005552b385SBrandon 
40015552b385SBrandon       if (!fHashKeyFound) {
40025552b385SBrandon         PetscCall(PetscHMapISet(currFaceUniquePoints, fIndices[jj], cfCntr));
40035552b385SBrandon         cfCntr += 1;
40045552b385SBrandon       }
40055552b385SBrandon 
40065552b385SBrandon       PetscCall(PetscHMapIFind(pointSurfGradRow_Start, fIndices[jj], &pHashKeyIter, &pHashKeyFound));
40075552b385SBrandon 
40085552b385SBrandon       if (!pHashKeyFound) {
40095552b385SBrandon         PetscCall(PetscHMapISet(pointSurfGradRow_Start, fIndices[jj], gcntr));
40105552b385SBrandon         gcntr += 3 * maxNumCPs;
40115552b385SBrandon       }
40125552b385SBrandon     }
40135552b385SBrandon     PetscCall(ISRestoreIndices(facePoints, &fIndices));
40145552b385SBrandon     PetscCall(ISDestroy(&facePoints));
40155552b385SBrandon 
40165552b385SBrandon     // 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.
40175552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
40185552b385SBrandon       ego       edge = eobjs[jj];
40195552b385SBrandon       PetscBool containLabelValue;
40205552b385SBrandon 
40215552b385SBrandon       if (islite) {
40225552b385SBrandon         id = EGlite_indexBodyTopo(body, edge);
40235552b385SBrandon       } else {
40245552b385SBrandon         id = EG_indexBodyTopo(body, edge);
40255552b385SBrandon       }
40265552b385SBrandon 
40275552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
40285552b385SBrandon       PetscCall(DMLabelHasValue(edgeLabel, id, &containLabelValue));
40295552b385SBrandon 
40305552b385SBrandon       if (containLabelValue) {
40315552b385SBrandon         PetscCall(DMLabelGetStratumIS(edgeLabel, id, &edgePoints));
40325552b385SBrandon         PetscCall(ISGetIndices(edgePoints, &eIndices));
40335552b385SBrandon         PetscCall(ISGetSize(edgePoints, &eSize));
40345552b385SBrandon 
40355552b385SBrandon         for (int kk = 0; kk < eSize; ++kk) {
40365552b385SBrandon           PetscCall(PetscHMapIFind(currFaceUniquePoints, eIndices[kk], &eHashKeyIter, &eHashKeyFound));
40375552b385SBrandon 
40385552b385SBrandon           if (!eHashKeyFound) {
40395552b385SBrandon             PetscCall(PetscHMapISet(currFaceUniquePoints, eIndices[kk], cfCntr));
40405552b385SBrandon             cfCntr += 1;
40415552b385SBrandon           }
40425552b385SBrandon 
40435552b385SBrandon           PetscCall(PetscHMapIFind(pointSurfGradRow_Start, eIndices[kk], &pHashKeyIter, &pHashKeyFound));
40445552b385SBrandon 
40455552b385SBrandon           if (!pHashKeyFound) {
40465552b385SBrandon             PetscCall(PetscHMapISet(pointSurfGradRow_Start, eIndices[kk], gcntr));
40475552b385SBrandon             gcntr += 3 * maxNumCPs;
40485552b385SBrandon           }
40495552b385SBrandon         }
40505552b385SBrandon         PetscCall(ISRestoreIndices(edgePoints, &eIndices));
40515552b385SBrandon         PetscCall(ISDestroy(&edgePoints));
40525552b385SBrandon       }
40535552b385SBrandon     }
40545552b385SBrandon 
40555552b385SBrandon     // 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.
40565552b385SBrandon     for (int jj = 0; jj < Nn; ++jj) {
40575552b385SBrandon       ego node = nobjs[jj];
40585552b385SBrandon 
40595552b385SBrandon       if (islite) {
40605552b385SBrandon         id = EGlite_indexBodyTopo(body, node);
40615552b385SBrandon       } else {
40625552b385SBrandon         id = EG_indexBodyTopo(body, node);
40635552b385SBrandon       }
40645552b385SBrandon 
40655552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &nodeLabel));
40665552b385SBrandon       PetscCall(DMLabelGetStratumIS(nodeLabel, id, &nodePoints));
40675552b385SBrandon       PetscCall(ISGetIndices(nodePoints, &nIndices));
40685552b385SBrandon       PetscCall(ISGetSize(nodePoints, &nSize));
40695552b385SBrandon 
40705552b385SBrandon       for (int kk = 0; kk < nSize; ++kk) {
40715552b385SBrandon         PetscCall(PetscHMapIFind(currFaceUniquePoints, nIndices[kk], &nHashKeyIter, &nHashKeyFound));
40725552b385SBrandon 
40735552b385SBrandon         if (!nHashKeyFound) {
40745552b385SBrandon           PetscCall(PetscHMapISet(currFaceUniquePoints, nIndices[kk], cfCntr));
40755552b385SBrandon           cfCntr += 1;
40765552b385SBrandon         }
40775552b385SBrandon 
40785552b385SBrandon         PetscCall(PetscHMapIFind(pointSurfGradRow_Start, nIndices[kk], &pHashKeyIter, &pHashKeyFound));
40795552b385SBrandon         if (!pHashKeyFound) {
40805552b385SBrandon           PetscCall(PetscHMapISet(pointSurfGradRow_Start, nIndices[kk], gcntr));
40815552b385SBrandon           gcntr += 3 * maxNumCPs;
40825552b385SBrandon         }
40835552b385SBrandon       }
40845552b385SBrandon       PetscCall(ISRestoreIndices(nodePoints, &nIndices));
40855552b385SBrandon       PetscCall(ISDestroy(&nodePoints));
40865552b385SBrandon     }
40875552b385SBrandon 
40885552b385SBrandon     // Get the Total Number of entries in the Hash Table
40895552b385SBrandon     PetscInt currFaceUPSize;
40905552b385SBrandon     PetscCall(PetscHMapIGetSize(currFaceUniquePoints, &currFaceUPSize));
40915552b385SBrandon 
40925552b385SBrandon     // Get Keys
40935552b385SBrandon     PetscInt currFaceUPKeys[currFaceUPSize], off = 0;
40945552b385SBrandon     PetscCall(PetscHMapIGetKeys(currFaceUniquePoints, &off, currFaceUPKeys));
40955552b385SBrandon     PetscCall(PetscHMapIDestroy(&currFaceUniquePoints));
40965552b385SBrandon 
40975552b385SBrandon     // Get Current Face Surface Area
40985552b385SBrandon     PetscScalar fSA, faceData[14];
40995552b385SBrandon     PetscCall(EG_getMassProperties(face, faceData)); // This doesn't have a EGlite version. Will it work for EGADSlite files??  KNOWN_ISSUE
41005552b385SBrandon     fSA = faceData[1];
41015552b385SBrandon 
41025552b385SBrandon     // Get Start Row in cpEquiv Matrix
41035552b385SBrandon     PetscHashIter Witer;
41045552b385SBrandon     PetscBool     Wfound;
41055552b385SBrandon     PetscInt      faceWStartRow;
41065552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, fid, &Witer, &Wfound));
41075552b385SBrandon     PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
41085552b385SBrandon     PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, fid, &faceWStartRow));
41095552b385SBrandon 
41105552b385SBrandon     // Cycle through all points on the current FACE
41115552b385SBrandon     for (int jj = 0; jj < currFaceUPSize; ++jj) {
41125552b385SBrandon       PetscInt currPointID = currFaceUPKeys[jj];
41135552b385SBrandon       PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
41145552b385SBrandon 
41155552b385SBrandon       // Get UV position of FACE
41165552b385SBrandon       double params[2], range[4], eval[18];
41175552b385SBrandon       int    peri;
41185552b385SBrandon 
41195552b385SBrandon       if (islite) PetscCall(EGlite_getRange(face, range, &peri));
41205552b385SBrandon       else PetscCall(EG_getRange(face, range, &peri));
41215552b385SBrandon 
41225552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
41235552b385SBrandon 
41245552b385SBrandon       if (islite) PetscCall(EGlite_evaluate(face, params, eval));
41255552b385SBrandon       else PetscCall(EG_evaluate(face, params, eval));
41265552b385SBrandon 
41275552b385SBrandon       // Make a new SURFACE Geometry by changing the location of the Control Points
41285552b385SBrandon       int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
41295552b385SBrandon       double nbprv[prvSize];
41305552b385SBrandon 
41315552b385SBrandon       // Cycle through each Control Point
41325552b385SBrandon       double denomNew, denomOld;
41335552b385SBrandon       double deltaCoord = 1.0E-4;
41345552b385SBrandon       int    offset     = bpinfo[3] + bpinfo[6];
41355552b385SBrandon       int    wOffset    = offset + (3 * bpinfo[2] * bpinfo[5]);
41365552b385SBrandon       for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) {
41375552b385SBrandon         PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d", f, jj, ii);
41385552b385SBrandon   #if 0
41395552b385SBrandon         // Cycle through each direction (x, then y, then z)
41405552b385SBrandon         if (jj == 0) {
41415552b385SBrandon           // Get the Number Control Points that are the same as the current points
41425552b385SBrandon           //    We are looking for repeated Control Points
41435552b385SBrandon           PetscInt commonCPcntr = 0;
41445552b385SBrandon           for (int mm = 0; mm < bpinfo[2]*bpinfo[5]; ++mm) {
41455552b385SBrandon             PetscScalar matValue;
41465552b385SBrandon             PetscCall(MatGetValue(cpEquiv, faceWStartRow + ii, faceWStartRow + mm, &matValue));
41475552b385SBrandon 
41485552b385SBrandon             if (matValue > 0.0) commonCPcntr += 1;
41495552b385SBrandon           }
41505552b385SBrandon         }
41515552b385SBrandon   #endif
41525552b385SBrandon 
41535552b385SBrandon         for (int kk = 0; kk < 4; ++kk) {
41545552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
4155ac530a7eSPierre Jolivet           for (int mm = 0; mm < prvSize; ++mm) nbprv[mm] = bprv[mm];
41565552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
41575552b385SBrandon 
41585552b385SBrandon           if (kk == 0) { //X
41595552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0] + deltaCoord;
41605552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
41615552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
41625552b385SBrandon             denomNew          = nbprv[offset + 0];
41635552b385SBrandon             denomOld          = bprv[offset + 0];
41645552b385SBrandon           } else if (kk == 1) { //Y
41655552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
41665552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1] + deltaCoord;
41675552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
41685552b385SBrandon             denomNew          = nbprv[offset + 1];
41695552b385SBrandon             denomOld          = bprv[offset + 1];
41705552b385SBrandon           } else if (kk == 2) { //Z
41715552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
41725552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
41735552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2] + deltaCoord;
41745552b385SBrandon             denomNew          = nbprv[offset + 2];
41755552b385SBrandon             denomOld          = bprv[offset + 2];
41765552b385SBrandon           } else if (kk == 3) { // Weights
41775552b385SBrandon             nbprv[wOffset + ii] = bprv[wOffset + ii] + deltaCoord;
41785552b385SBrandon             denomNew            = nbprv[wOffset + ii];
41795552b385SBrandon             denomOld            = bprv[wOffset + ii];
41805552b385SBrandon           } else {
41815552b385SBrandon             // currently do nothing
41825552b385SBrandon           }
41835552b385SBrandon 
41845552b385SBrandon           // Create New Surface Based on New Control Points or Weights
41855552b385SBrandon           ego newgeom, context;
41865552b385SBrandon           PetscCallEGADS(EG_getContext, (face, &context));                                             // This does not have an EGlite_ version KNOWN_ISSUE
41875552b385SBrandon           PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // This does not have an EGlite_ version KNOWN_ISSUE
41885552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
41895552b385SBrandon 
41905552b385SBrandon           // Evaluate new (x, y, z) Point Position based on new Surface Definition
41915552b385SBrandon           double newCoords[18];
41925552b385SBrandon           if (islite) PetscCall(EGlite_getRange(newgeom, range, &peri));
41935552b385SBrandon           else PetscCall(EG_getRange(newgeom, range, &peri));
41945552b385SBrandon 
41955552b385SBrandon           PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
41965552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
41975552b385SBrandon 
41985552b385SBrandon           if (islite) PetscCall(EGlite_evaluate(newgeom, params, newCoords));
41995552b385SBrandon           else PetscCall(EG_evaluate(newgeom, params, newCoords));
42005552b385SBrandon 
42015552b385SBrandon           // Calculate Surface Area Gradients wrt Control Points and Weights using the local discrete FACE only
42025552b385SBrandon           //      NOTE 1: Will not provide Volume Gradient wrt to Control Points and Weights.
42035552b385SBrandon           //      NOTE 2: This is faster than below where an entire new solid geometry is created for each
42045552b385SBrandon           //              Control Point and Weight gradient
42055552b385SBrandon           if (!fullGeomGrad) {
42065552b385SBrandon             // Create new FACE based on new SURFACE geometry
42075552b385SBrandon             if (jj == 0) { // only for 1st DMPlex Point because we only per CP or Weight
42085552b385SBrandon               double newFaceRange[4];
42095552b385SBrandon               int    newFacePeri;
42105552b385SBrandon               if (islite) PetscCall(EGlite_getRange(newgeom, newFaceRange, &newFacePeri));
42115552b385SBrandon               else PetscCall(EG_getRange(newgeom, newFaceRange, &newFacePeri));
42125552b385SBrandon 
42135552b385SBrandon               ego newface;
42145552b385SBrandon               PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, newFaceRange, &newface)); // Does not have EGlite version KNOWN_ISSUE
42155552b385SBrandon               PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
42165552b385SBrandon 
42175552b385SBrandon               // Get New Face Surface Area
42185552b385SBrandon               PetscScalar newfSA, newFaceData[14];
42195552b385SBrandon               PetscCall(EG_getMassProperties(newface, newFaceData)); // Does not have EGlite version KNOWN_ISSUE
42205552b385SBrandon               newfSA = newFaceData[1];
42215552b385SBrandon               PetscCallEGADS(EG_deleteObject, (newface));
42225552b385SBrandon               PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
42235552b385SBrandon 
42245552b385SBrandon               // Update Control Points
42255552b385SBrandon               PetscHashIter CPiter, Witer;
42265552b385SBrandon               PetscBool     CPfound, Wfound;
42275552b385SBrandon               PetscInt      faceCPStartRow, faceWStartRow;
42285552b385SBrandon 
42295552b385SBrandon               PetscScalar dSAdCPi;
42305552b385SBrandon               dSAdCPi = (newfSA - fSA) / (denomNew - denomOld);
42315552b385SBrandon 
42325552b385SBrandon               if (kk < 3) {
42335552b385SBrandon                 PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, fid, &CPiter, &CPfound));
42345552b385SBrandon                 PetscCheck(CPfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
42355552b385SBrandon                 PetscCall(PetscHMapIGet(faceCntrlPtRow_Start, fid, &faceCPStartRow));
42365552b385SBrandon 
42375552b385SBrandon                 gradSACP[faceCPStartRow + (ii * 3) + kk] = dSAdCPi;
42385552b385SBrandon 
42395552b385SBrandon                 if (PetscAbsReal(dSAdCPi) > maxGrad) maxGrad = PetscAbsReal(dSAdCPi);
42405552b385SBrandon 
42415552b385SBrandon               } else if (kk == 3) {
42425552b385SBrandon                 PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, fid, &Witer, &Wfound));
42435552b385SBrandon                 PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
42445552b385SBrandon                 PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, fid, &faceWStartRow));
42455552b385SBrandon 
42465552b385SBrandon                 gradSAW[faceWStartRow + ii] = dSAdCPi;
42475552b385SBrandon 
42485552b385SBrandon               } else {
42495552b385SBrandon                 // Do Nothing
42505552b385SBrandon               }
42515552b385SBrandon             }
42525552b385SBrandon           }
42535552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newgeom));
42545552b385SBrandon 
42555552b385SBrandon           // Now Calculate the Surface Gradient for the change in x-component Control Point
42565552b385SBrandon           PetscScalar dxdCx = (newCoords[0] - coords[0]) / deltaCoord;
42575552b385SBrandon           PetscScalar dxdCy = (newCoords[1] - coords[1]) / deltaCoord;
42585552b385SBrandon           PetscScalar dxdCz = (newCoords[2] - coords[2]) / deltaCoord;
42595552b385SBrandon 
42605552b385SBrandon           // Store Gradient Information in surfaceGrad[][] Matrix
42615552b385SBrandon           PetscInt startRow;
42625552b385SBrandon           PetscCall(PetscHMapIGet(pointSurfGradRow_Start, currPointID, &startRow));
42635552b385SBrandon 
4264f0b74427SPierre Jolivet           // Store Results in PETSc Mat
42655552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 0, ((fid - 1) * 4) + kk, dxdCx, INSERT_VALUES));
42665552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 1, ((fid - 1) * 4) + kk, dxdCy, INSERT_VALUES));
42675552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 2, ((fid - 1) * 4) + kk, dxdCz, INSERT_VALUES));
42685552b385SBrandon 
42695552b385SBrandon           //PetscCallEGADS(EG_deleteObject, (newgeom));
42705552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face is corrupted");
42715552b385SBrandon         }
42725552b385SBrandon         offset += 3;
42735552b385SBrandon       }
42745552b385SBrandon       PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
42755552b385SBrandon     }
42765552b385SBrandon   }
42775552b385SBrandon 
42785552b385SBrandon   // Assemble Point Surface Grad Matrix
42795552b385SBrandon   PetscCall(MatAssemblyBegin(pointSurfGrad, MAT_FINAL_ASSEMBLY));
42805552b385SBrandon   PetscCall(MatAssemblyEnd(pointSurfGrad, MAT_FINAL_ASSEMBLY));
42815552b385SBrandon 
42825552b385SBrandon   if (fullGeomGrad) {
42835552b385SBrandon     // Calculate Surface Area and Volume Control Point and Control Point Weight Gradients
42845552b385SBrandon     //    Note: This is much slower than above due to a new solid geometry being created for
42855552b385SBrandon     //          each change in Control Point and Control Point Weight. However, this method
42865552b385SBrandon     //          will provide the Volume Gradient.
42875552b385SBrandon 
42885552b385SBrandon     // Get Current Face Surface Area
42895552b385SBrandon     PetscScalar bodyVol, bodySA, bodyData[14];
4290bfe80ac4SPierre Jolivet     PetscCall(EG_getMassProperties(body, bodyData)); // Does not have an EGlite version KNOWN_ISSUE
42915552b385SBrandon     bodyVol = bodyData[0];
42925552b385SBrandon     bodySA  = bodyData[1];
42935552b385SBrandon 
42945552b385SBrandon     // Cycle through Control Points
42955552b385SBrandon     for (int ii = 0; ii < totalNumCPs; ++ii) { // ii should also be the row in cpEquiv for the Control Point
42965552b385SBrandon       // Cycle through X, Y, Z, W changes
42975552b385SBrandon       for (int jj = 0; jj < 4; ++jj) {
42985552b385SBrandon         // Cycle Through Faces
42995552b385SBrandon         double denomNew = 0.0, denomOld = 0.0;
43005552b385SBrandon         double deltaCoord = 1.0E-4;
43015552b385SBrandon         ego    newGeom[Nf];
43025552b385SBrandon         ego    newFaces[Nf];
43035552b385SBrandon         for (int kk = 0; kk < Nf; ++kk) {
43045552b385SBrandon           ego      face;
43055552b385SBrandon           PetscInt currFID = kk + 1;
43065552b385SBrandon 
43075552b385SBrandon           if (islite) {
43085552b385SBrandon             // Get Current FACE
43095552b385SBrandon             PetscCallEGADS(EGlite_objectBodyTopo, (body, FACE, currFID, &face));
43105552b385SBrandon 
43115552b385SBrandon             // Get Geometry Object for the Current FACE
43125552b385SBrandon             PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
43135552b385SBrandon             PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
43145552b385SBrandon           } else {
43155552b385SBrandon             // Get Current FACE
43165552b385SBrandon             PetscCallEGADS(EG_objectBodyTopo, (body, FACE, currFID, &face));
43175552b385SBrandon 
43185552b385SBrandon             // Get Geometry Object for the Current FACE
43195552b385SBrandon             PetscCallEGADS(EG_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
43205552b385SBrandon             PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
43215552b385SBrandon           }
43225552b385SBrandon 
43235552b385SBrandon           // Make a new SURFACE Geometry by changing the location of the Control Points
43245552b385SBrandon           int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
43255552b385SBrandon           double nbprv[prvSize];
43265552b385SBrandon 
43275552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
43285552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) nbprv[mm] = bprv[mm];
43295552b385SBrandon 
43305552b385SBrandon           // Get Control Point Row and Column Start for cpEquiv
43315552b385SBrandon           PetscHashIter Witer;
43325552b385SBrandon           PetscBool     Wfound;
43335552b385SBrandon           PetscInt      faceWStartRow;
43345552b385SBrandon           PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, currFID, &Witer, &Wfound));
43355552b385SBrandon           PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
43365552b385SBrandon           PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, currFID, &faceWStartRow));
43375552b385SBrandon 
43385552b385SBrandon           // Modify the Current Control Point on this FACE and All Other FACES
43395552b385SBrandon           // IMPORTANT!!! If you do not move all identical Control Points on other FACES
43405552b385SBrandon           //              you will not generate a solid body. You will generate a set of
43415552b385SBrandon           //              disconnected surfaces that have gap(s) between them.
43425552b385SBrandon           int offset  = bpinfo[3] + bpinfo[6];
43435552b385SBrandon           int wOffset = offset + (3 * bpinfo[2] * bpinfo[5]);
43445552b385SBrandon           for (int mm = 0; mm < bpinfo[2] * bpinfo[5]; ++mm) {
43455552b385SBrandon             PetscScalar matValue;
43465552b385SBrandon             PetscCall(MatGetValue(cpEquiv, ii, faceWStartRow + mm, &matValue));
43475552b385SBrandon 
43485552b385SBrandon             if (matValue > 0.0) {
43495552b385SBrandon               if (jj == 0) { //X
43505552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0] + deltaCoord;
43515552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1];
43525552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2];
43535552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 0];
43545552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 0];
43555552b385SBrandon               } else if (jj == 1) { //Y
43565552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0];
43575552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1] + deltaCoord;
43585552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2];
43595552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 1];
43605552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 1];
43615552b385SBrandon               } else if (jj == 2) { //Z
43625552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0];
43635552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1];
43645552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2] + deltaCoord;
43655552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 2];
43665552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 2];
43675552b385SBrandon               } else if (jj == 3) { // Weights
43685552b385SBrandon                 nbprv[wOffset + mm] = bprv[wOffset + mm] + deltaCoord;
43695552b385SBrandon                 denomNew            = nbprv[wOffset + mm];
43705552b385SBrandon                 denomOld            = bprv[wOffset + mm];
43715552b385SBrandon               } else {
43725552b385SBrandon                 // currently do nothing
43735552b385SBrandon               }
43745552b385SBrandon             }
43755552b385SBrandon           }
43765552b385SBrandon 
43775552b385SBrandon           // Create New Surface Based on New Control Points or Weights
43785552b385SBrandon           ego newgeom, context;
43795552b385SBrandon           PetscCallEGADS(EG_getContext, (face, &context));                                             // Does not have an EGlite_ versions   KNOWN_ISSUE
43805552b385SBrandon           PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
43815552b385SBrandon 
43825552b385SBrandon           // Create New FACE based on modified geometry
43835552b385SBrandon           double newFaceRange[4];
43845552b385SBrandon           int    newFacePeri;
43855552b385SBrandon           if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, newFaceRange, &newFacePeri));
43865552b385SBrandon           else PetscCallEGADS(EG_getRange, (newgeom, newFaceRange, &newFacePeri));
43875552b385SBrandon 
43885552b385SBrandon           ego newface;
43895552b385SBrandon           PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, newFaceRange, &newface)); // Does not have an EGlite_ version KNOWN_ISSUE
43905552b385SBrandon 
43915552b385SBrandon           // store new face for later assembly
43925552b385SBrandon           newGeom[kk]  = newgeom;
43935552b385SBrandon           newFaces[kk] = newface;
43945552b385SBrandon         }
43955552b385SBrandon 
43965552b385SBrandon         // X-WANT TO BUILD THE NEW GEOMETRY, X-GET NEW SA AND PERFORM dSA/dCPi CALCS HERE <---
43975552b385SBrandon         // Sew New Faces together to get a new model
43985552b385SBrandon         ego newmodel;
43995552b385SBrandon         PetscCall(EG_sewFaces(Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version KNOWN_ISSUE
44005552b385SBrandon 
44015552b385SBrandon         // Get Surface Area and Volume of New/Updated Solid Body
44025552b385SBrandon         PetscScalar newData[14];
44035552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getTopology, (newmodel, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
44045552b385SBrandon         else PetscCallEGADS(EG_getTopology, (newmodel, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
44055552b385SBrandon 
44065552b385SBrandon         ego nbody = bodies[0];
44075552b385SBrandon         PetscCall(EG_getMassProperties(nbody, newData)); // Does not have an EGlite_ version   KNOWN_ISSUE
44085552b385SBrandon 
44095552b385SBrandon         PetscScalar dSAdCPi, dVdCPi;
44105552b385SBrandon         PetscScalar nbodyVol = newData[0], nbodySA = newData[1];
44115552b385SBrandon 
44125552b385SBrandon         // Calculate Gradients wrt to Control Points and Control Points Weights depending on jj value
44135552b385SBrandon         dSAdCPi = (nbodySA - bodySA) / (denomNew - denomOld);
44145552b385SBrandon         dVdCPi  = (nbodyVol - bodyVol) / (denomNew - denomOld);
44155552b385SBrandon 
44165552b385SBrandon         if (jj < 3) {
44175552b385SBrandon           // Gradienst wrt to Control Points
44185552b385SBrandon           gradSACP[(ii * 3) + jj] = dSAdCPi;
44195552b385SBrandon           gradVCP[(ii * 3) + jj]  = dVdCPi;
44205552b385SBrandon         } else if (jj == 3) {
44215552b385SBrandon           // Gradients wrt to Control Point Weights
44225552b385SBrandon           gradSAW[ii] = dSAdCPi;
44235552b385SBrandon           gradVW[ii]  = dVdCPi;
44245552b385SBrandon         } else {
44255552b385SBrandon           // Do Nothing
44265552b385SBrandon         }
44275552b385SBrandon         PetscCallEGADS(EG_deleteObject, (newmodel));
44285552b385SBrandon         for (int kk = 0; kk < Nf; ++kk) {
44295552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newFaces[kk]));
44305552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newGeom[kk]));
44315552b385SBrandon         }
44325552b385SBrandon       }
44335552b385SBrandon     }
44345552b385SBrandon   }
44355552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradSACPVec, &gradSACP));
44365552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradSAWVec, &gradSAW));
44375552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradVCPVec, &gradVCP));
44385552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradVWVec, &gradVW));
44395552b385SBrandon   PetscCall(MatDestroy(&cpEquiv));
44405552b385SBrandon 
44415552b385SBrandon   // Attach Surface Gradient Hash Table and Matrix to DM
44425552b385SBrandon   {
44435552b385SBrandon     PetscContainer surfGradOrgObj;
44445552b385SBrandon 
44455552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject *)&surfGradOrgObj));
44465552b385SBrandon     if (!surfGradOrgObj) {
44475552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradOrgObj));
44485552b385SBrandon       PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
44495552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(surfGradOrgObj, DestroyHashMap));
44505552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject)surfGradOrgObj));
44515552b385SBrandon       PetscCall(PetscContainerDestroy(&surfGradOrgObj));
44525552b385SBrandon     } else {
44535552b385SBrandon       PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
44545552b385SBrandon     }
44555552b385SBrandon 
44565552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Matrix", (PetscObject)pointSurfGrad));
44575552b385SBrandon     PetscCall(MatDestroy(&pointSurfGrad));
44585552b385SBrandon 
44595552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject)gradSACPVec));
44605552b385SBrandon     PetscCall(VecDestroy(&gradSACPVec));
44615552b385SBrandon 
44625552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject)gradSAWVec));
44635552b385SBrandon     PetscCall(VecDestroy(&gradSAWVec));
44645552b385SBrandon 
44655552b385SBrandon     if (fullGeomGrad) {
44665552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Volume Control Point Gradient", (PetscObject)gradVCPVec));
44675552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Volume Weights Gradient", (PetscObject)gradVWVec));
44685552b385SBrandon     }
44695552b385SBrandon     PetscCall(VecDestroy(&gradVCPVec));
44705552b385SBrandon     PetscCall(VecDestroy(&gradVWVec));
44715552b385SBrandon   }
44725552b385SBrandon 
44735552b385SBrandon   // Could be replaced with DMPlexFreeGeomObject()
44745552b385SBrandon   if (islite) EGlite_free(fobjs);
44755552b385SBrandon   else EG_free(fobjs);
44765552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
44775552b385SBrandon #else
44785552b385SBrandon   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
44795552b385SBrandon #endif
44805552b385SBrandon }
44815552b385SBrandon 
44825552b385SBrandon /*@C
44835552b385SBrandon   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.
44845552b385SBrandon 
44855552b385SBrandon   Collective
44865552b385SBrandon 
44875552b385SBrandon   Input Parameters:
44885552b385SBrandon + dm          - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
44895552b385SBrandon . comm        - MPI_Comm object
44905552b385SBrandon . newCP       - C Array of [x, y, z] New/Updated Control Point Coordinates defining the geometry (See DMPlexGeomDataAndGrads() for format)
44915552b385SBrandon . newW        - C Array of New/Updated Control Point Weights associated with the Control Points defining the new geometry (See DMPlexGemGrads() for format)
44925552b385SBrandon . autoInflate - PetscBool Flag denoting if the user would like to inflate the DM points to the new geometry.
44935552b385SBrandon . saveGeom    - PetscBool Flag denoting if the user would iike to save the new geometry to a file.
44945552b385SBrandon - 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.
44955552b385SBrandon                       *.stp or *.step = STEP File
44965552b385SBrandon                       *.igs or *.iges = IGES File
44975552b385SBrandon                               *.egads = EGADS File
44985552b385SBrandon                                *.brep = BRep File (OpenCASCADE File)
44995552b385SBrandon 
45005552b385SBrandon   Output Parameter:
45015552b385SBrandon . dm - The updated DM object representing the mesh with PetscContainers containing the updated/modified geometry
45025552b385SBrandon 
45035552b385SBrandon   Level: intermediate
45045552b385SBrandon 
45055552b385SBrandon   Note:
45065552b385SBrandon   Functionality not available for DMPlexes with attached EGADSlite geometry files (.egadslite).
45075552b385SBrandon 
45085552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`
45095552b385SBrandon @*/
DMPlexModifyGeomModel(DM dm,MPI_Comm comm,PetscScalar newCP[],PetscScalar newW[],PetscBool autoInflate,PetscBool saveGeom,const char * stpName)4510ce78bad3SBarry Smith PetscErrorCode DMPlexModifyGeomModel(DM dm, MPI_Comm comm, PetscScalar newCP[], PetscScalar newW[], PetscBool autoInflate, PetscBool saveGeom, const char *stpName) PeNS
45115552b385SBrandon {
45125552b385SBrandon #if defined(PETSC_HAVE_EGADS)
45135552b385SBrandon   /* EGADS/EGADSlite variables */
45145552b385SBrandon   ego context, model, geom, *bodies, *lobjs, *fobjs;
45155552b385SBrandon   int oclass, mtype, *senses, *lsenses;
45165552b385SBrandon   int Nb, Nf, Nl, id;
45175552b385SBrandon   /* PETSc variables */
45185552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
45195552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj;
45205552b385SBrandon   PetscHMapI     cpHashTable = NULL, wHashTable = NULL;
45215552b385SBrandon   PetscBool      islite = PETSC_FALSE;
45225552b385SBrandon #endif
45235552b385SBrandon 
45245552b385SBrandon #if defined(PETSC_HAVE_EGADS)
45255552b385SBrandon   PetscFunctionBegin;
45265552b385SBrandon   // Look to see if DM has a Container with either a EGADS or EGADSlite Model
45275552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
45285552b385SBrandon   if (!modelObj) {
45295552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
45305552b385SBrandon     islite = PETSC_TRUE;
45315552b385SBrandon   }
45325552b385SBrandon   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");
45335552b385SBrandon   PetscCheck(modelObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "DM does not have a EGADS Geometry Model attached to it!");
45345552b385SBrandon 
45355552b385SBrandon   // Get attached EGADS model (pointer)
45362a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
45375552b385SBrandon 
45385552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
45395552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
45405552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
45415552b385SBrandon 
45425552b385SBrandon   PetscCheck(cpHashTableObj && wHashTableObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "DM does not have required Geometry Data attached! Please run DMPlexGeomDataAndGrads() Function first.");
45435552b385SBrandon 
45445552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
45452a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(cpHashTableObj, &cpHashTable));
45462a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(wHashTableObj, &wHashTable));
45475552b385SBrandon 
45485552b385SBrandon   // Get the number of bodies and body objects in the model
45495552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
45505552b385SBrandon   else PetscCallEGADS(EG_getTopology, (model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
45515552b385SBrandon 
45525552b385SBrandon   // Get all Faces on the body
45535552b385SBrandon   ego body = bodies[0];
45545552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
45555552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
45565552b385SBrandon 
45575552b385SBrandon   ego newGeom[Nf];
45585552b385SBrandon   ego newFaces[Nf];
45595552b385SBrandon 
45605552b385SBrandon   // Update Control Point and Weight definitions for each surface
45615552b385SBrandon   for (int jj = 0; jj < Nf; ++jj) {
45625552b385SBrandon     ego     face = fobjs[jj];
45635552b385SBrandon     ego     bRef, bPrev, bNext;
45645552b385SBrandon     ego     fgeom;
45655552b385SBrandon     int     offset;
45665552b385SBrandon     int     boclass, bmtype, *bpinfo;
45675552b385SBrandon     double *bprv;
45685552b385SBrandon 
45695552b385SBrandon     // Get FACE ID and other Geometry Data
45705552b385SBrandon     if (islite) {
45715552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
45725552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
45735552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
45745552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
45755552b385SBrandon     } else {
45765552b385SBrandon       id = EG_indexBodyTopo(body, face);
45775552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &fgeom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
45785552b385SBrandon       PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
45795552b385SBrandon       PetscCallEGADS(EG_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
45805552b385SBrandon     }
45815552b385SBrandon 
45825552b385SBrandon     // Update Control Points
45835552b385SBrandon     PetscHashIter CPiter, Witer;
45845552b385SBrandon     PetscBool     CPfound, Wfound;
45855552b385SBrandon     PetscInt      faceCPStartRow, faceWStartRow;
45865552b385SBrandon 
45875552b385SBrandon     PetscCall(PetscHMapIFind(cpHashTable, id, &CPiter, &CPfound));
45885552b385SBrandon     PetscCheck(CPfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
45895552b385SBrandon     PetscCall(PetscHMapIGet(cpHashTable, id, &faceCPStartRow));
45905552b385SBrandon 
45915552b385SBrandon     PetscCall(PetscHMapIFind(wHashTable, id, &Witer, &Wfound));
45925552b385SBrandon     PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
45935552b385SBrandon     PetscCall(PetscHMapIGet(wHashTable, id, &faceWStartRow));
45945552b385SBrandon 
45955552b385SBrandon     // UPDATE CONTROL POINTS Locations
45965552b385SBrandon     offset = bpinfo[3] + bpinfo[6];
4597ac530a7eSPierre Jolivet     for (int ii = 0; ii < 3 * bpinfo[2] * bpinfo[5]; ++ii) bprv[offset + ii] = newCP[faceCPStartRow + ii];
45985552b385SBrandon 
45995552b385SBrandon     // UPDATE CONTROL POINT WEIGHTS
46005552b385SBrandon     offset = bpinfo[3] + bpinfo[6] + 3 * bpinfo[2] * bpinfo[5];
4601ac530a7eSPierre Jolivet     for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) bprv[offset + ii] = newW[faceWStartRow + ii];
46025552b385SBrandon 
46035552b385SBrandon     // Get Context from FACE
46045552b385SBrandon     context = NULL;
46055552b385SBrandon     PetscCallEGADS(EG_getContext, (face, &context)); // Does not have an EGlite_ version  KNOWN_ISSUE
46065552b385SBrandon 
46075552b385SBrandon     // Create New Surface
46085552b385SBrandon     ego newgeom;
46095552b385SBrandon     PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, bprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
46105552b385SBrandon 
46115552b385SBrandon     // Create new FACE based on new SURFACE geometry
46125552b385SBrandon     double data[4];
46135552b385SBrandon     int    periodic;
46145552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, data, &periodic));
46155552b385SBrandon     else PetscCallEGADS(EG_getRange, (newgeom, data, &periodic));
46165552b385SBrandon 
46175552b385SBrandon     ego newface;
46185552b385SBrandon     PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, data, &newface)); // Does not have an EGlite_ version KNOWN_ISSUE
46195552b385SBrandon     newGeom[jj]  = newgeom;
46205552b385SBrandon     newFaces[jj] = newface;
46215552b385SBrandon   }
46225552b385SBrandon   // Could be replaced by DMPlexFreeGeomObject
46235552b385SBrandon   if (islite) EGlite_free(fobjs);
46245552b385SBrandon   else EG_free(fobjs);
46255552b385SBrandon 
46265552b385SBrandon   // Sew New Faces together to get a new model
46275552b385SBrandon   ego newmodel;
46285552b385SBrandon   PetscCall(EG_sewFaces(Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version   KNOWN_ISSUE
46295552b385SBrandon   for (PetscInt f = 0; f < Nf; ++f) {
46305552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newFaces[f]));
46315552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newGeom[f]));
46325552b385SBrandon   }
46335552b385SBrandon 
46345552b385SBrandon   // Get the total number of NODEs on the original geometry. (This will be the same for the new geometry)
46355552b385SBrandon   int  totalNumNode;
46365552b385SBrandon   ego *nobjTotal;
46375552b385SBrandon   if (islite) {
46385552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, NODE, &totalNumNode, &nobjTotal));
46395552b385SBrandon     EGlite_free(nobjTotal);
46405552b385SBrandon   } else {
46415552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (body, NULL, NODE, &totalNumNode, &nobjTotal));
46425552b385SBrandon     EG_free(nobjTotal);
46435552b385SBrandon   } // Could be replaced with DMPlexFreeGeomObject
46445552b385SBrandon 
46455552b385SBrandon   // Initialize vector to store equivalent NODE indices between the 2 geometries
46465552b385SBrandon   // FORMAT :: vector index is the Original Geometry's NODE ID, the vector Value is the New Geometry's NODE ID
46475552b385SBrandon   int nodeIDEquiv[totalNumNode + 1];
46485552b385SBrandon 
46495552b385SBrandon   // Now we need to Map the NODE and EDGE IDs from each Model
46505552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
46515552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
46525552b385SBrandon 
46535552b385SBrandon   // New CAD
46545552b385SBrandon   ego *newbodies, newgeomtest, *nfobjs;
46555552b385SBrandon   int  nNf, newNb, newoclass, newmtype, *newsenses;
46565552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (newmodel, &newgeomtest, &newoclass, &newmtype, NULL, &newNb, &newbodies, &newsenses));
46575552b385SBrandon   else PetscCallEGADS(EG_getTopology, (newmodel, &newgeomtest, &newoclass, &newmtype, NULL, &newNb, &newbodies, &newsenses));
46585552b385SBrandon 
46595552b385SBrandon   ego newbody = newbodies[0];
46605552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (newbody, NULL, FACE, &nNf, &nfobjs));
46615552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (newbody, NULL, FACE, &nNf, &nfobjs));
46625552b385SBrandon 
46635552b385SBrandon   PetscCheck(newNb == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ERROR :: newNb > 1 || newNb = %d", newNb);
46645552b385SBrandon 
46655552b385SBrandon   // Find Equivalent Nodes
46665552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
46675552b385SBrandon     double fdata[4];
46685552b385SBrandon     int    peri;
46695552b385SBrandon 
46705552b385SBrandon     // Get Current FACE [u, v] Ranges
46715552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (fobjs[ii], fdata, &peri));
46725552b385SBrandon     else PetscCallEGADS(EG_getRange, (fobjs[ii], fdata, &peri));
46735552b385SBrandon 
46745552b385SBrandon     // Equate NODE IDs between 2 FACEs by working through (u, v) limits of FACE
46755552b385SBrandon     for (int jj = 0; jj < 2; ++jj) {
46765552b385SBrandon       for (int kk = 2; kk < 4; ++kk) {
46775552b385SBrandon         double params[2] = {fdata[jj], fdata[kk]};
46785552b385SBrandon         double eval[18];
46795552b385SBrandon         if (islite) PetscCallEGADS(EGlite_evaluate, (fobjs[ii], params, eval));
46805552b385SBrandon         else PetscCallEGADS(EG_evaluate, (fobjs[ii], params, eval));
46815552b385SBrandon 
46825552b385SBrandon         // Original Body
46835552b385SBrandon         ego *nobjsOrigFace;
46845552b385SBrandon         int  origNn;
46855552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, fobjs[ii], NODE, &origNn, &nobjsOrigFace));
46865552b385SBrandon         else PetscCallEGADS(EG_getBodyTopos, (body, fobjs[ii], NODE, &origNn, &nobjsOrigFace));
46875552b385SBrandon 
46885552b385SBrandon         double minVal = 1.0E10;
46895552b385SBrandon         double evalCheck[18];
46905552b385SBrandon         int    equivOrigNodeID = -1;
46915552b385SBrandon         for (int mm = 0; mm < origNn; ++mm) {
46925552b385SBrandon           double delta = 1.0E10;
46935552b385SBrandon           if (islite) PetscCallEGADS(EGlite_evaluate, (nobjsOrigFace[mm], NULL, evalCheck));
46945552b385SBrandon           else PetscCallEGADS(EG_evaluate, (nobjsOrigFace[mm], NULL, evalCheck));
46955552b385SBrandon 
46965552b385SBrandon           delta = PetscSqrtReal(PetscSqr(evalCheck[0] - eval[0]) + PetscSqr(evalCheck[1] - eval[1]) + PetscSqr(evalCheck[2] - eval[2]));
46975552b385SBrandon 
46985552b385SBrandon           if (delta < minVal) {
46995552b385SBrandon             if (islite) equivOrigNodeID = EGlite_indexBodyTopo(body, nobjsOrigFace[mm]);
47005552b385SBrandon             else equivOrigNodeID = EG_indexBodyTopo(body, nobjsOrigFace[mm]);
47015552b385SBrandon 
47025552b385SBrandon             minVal = delta;
47035552b385SBrandon           }
47045552b385SBrandon         }
47055552b385SBrandon         // Could be replaced with DMPlexFreeGeomObject
47065552b385SBrandon         if (islite) EGlite_free(nobjsOrigFace);
47075552b385SBrandon         else EG_free(nobjsOrigFace);
47085552b385SBrandon 
47095552b385SBrandon         // New Body
47105552b385SBrandon         ego *nobjsNewFace;
47115552b385SBrandon         int  newNn;
47125552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getBodyTopos, (newbody, nfobjs[ii], NODE, &newNn, &nobjsNewFace));
47135552b385SBrandon         else PetscCallEGADS(EG_getBodyTopos, (newbody, nfobjs[ii], NODE, &newNn, &nobjsNewFace));
47145552b385SBrandon 
47155552b385SBrandon         minVal             = 1.0E10;
47165552b385SBrandon         int equivNewNodeID = -1;
47175552b385SBrandon         for (int mm = 0; mm < newNn; ++mm) {
47185552b385SBrandon           double delta = 1.0E10;
47195552b385SBrandon           if (islite) PetscCallEGADS(EGlite_evaluate, (nobjsNewFace[mm], NULL, evalCheck));
47205552b385SBrandon           else PetscCallEGADS(EG_evaluate, (nobjsNewFace[mm], NULL, evalCheck));
47215552b385SBrandon 
47225552b385SBrandon           delta = PetscSqrtReal(PetscSqr(evalCheck[0] - eval[0]) + PetscSqr(evalCheck[1] - eval[1]) + PetscSqr(evalCheck[2] - eval[2]));
47235552b385SBrandon 
47245552b385SBrandon           if (delta < minVal) {
47255552b385SBrandon             if (islite) equivNewNodeID = EGlite_indexBodyTopo(newbody, nobjsNewFace[mm]);
47265552b385SBrandon             else equivNewNodeID = EG_indexBodyTopo(newbody, nobjsNewFace[mm]);
47275552b385SBrandon 
47285552b385SBrandon             minVal = delta;
47295552b385SBrandon           }
47305552b385SBrandon         }
47315552b385SBrandon         if (islite) EGlite_free(nobjsNewFace);
47325552b385SBrandon         else EG_free(nobjsNewFace);
47335552b385SBrandon 
47345552b385SBrandon         // Store equivalent NODE IDs
47355552b385SBrandon         nodeIDEquiv[equivOrigNodeID] = equivNewNodeID;
47365552b385SBrandon       }
47375552b385SBrandon     }
47385552b385SBrandon   }
47395552b385SBrandon 
47405552b385SBrandon   // Find Equivalent EDGEs
47415552b385SBrandon   //   Get total number of EDGEs on Original Geometry
47425552b385SBrandon   int  totalNumEdge;
47435552b385SBrandon   ego *eobjsOrig;
47445552b385SBrandon   if (islite) {
47455552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, EDGE, &totalNumEdge, &eobjsOrig));
47465552b385SBrandon     EGlite_free(eobjsOrig);
47475552b385SBrandon   } else {
47485552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (body, NULL, EDGE, &totalNumEdge, &eobjsOrig));
47495552b385SBrandon     EG_free(eobjsOrig);
47505552b385SBrandon   }
47515552b385SBrandon 
47525552b385SBrandon   //   Get total number of EDGEs on New Geometry
47535552b385SBrandon   int  totalNumEdgeNew;
47545552b385SBrandon   ego *eobjsNew;
47555552b385SBrandon   if (islite) {
47565552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (newbody, NULL, EDGE, &totalNumEdgeNew, &eobjsNew));
47575552b385SBrandon     EGlite_free(eobjsNew);
47585552b385SBrandon   } else {
47595552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (newbody, NULL, EDGE, &totalNumEdgeNew, &eobjsNew));
47605552b385SBrandon     EG_free(eobjsNew);
47615552b385SBrandon   }
47625552b385SBrandon 
47635552b385SBrandon   // Initialize EDGE ID equivalent vector
47645552b385SBrandon   // FORMAT :: vector index is the Original Geometry's EDGE ID, the vector Value is the New Geometry's EDGE ID
47655552b385SBrandon   int edgeIDEquiv[totalNumEdge + 1];
47665552b385SBrandon 
47675552b385SBrandon   // Find Equivalent EDGEs
47685552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
47695552b385SBrandon     // Get Original Geometry EDGE's NODEs
47705552b385SBrandon     int numOrigEdge, numNewEdge;
47715552b385SBrandon     if (islite) {
47725552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (body, fobjs[ii], EDGE, &numOrigEdge, &eobjsOrig));
47735552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (newbody, nfobjs[ii], EDGE, &numNewEdge, &eobjsNew));
47745552b385SBrandon     } else {
47755552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (body, fobjs[ii], EDGE, &numOrigEdge, &eobjsOrig));
47765552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (newbody, nfobjs[ii], EDGE, &numNewEdge, &eobjsNew));
47775552b385SBrandon     }
47785552b385SBrandon 
47795552b385SBrandon     // new loop below
47805552b385SBrandon     for (int nn = 0; nn < numOrigEdge; ++nn) {
47815552b385SBrandon       ego origEdge = eobjsOrig[nn];
47825552b385SBrandon       ego geomEdgeOrig, *nobjsOrig;
47835552b385SBrandon       int oclassEdgeOrig, mtypeEdgeOrig;
47845552b385SBrandon       int NnOrig, *nsensesEdgeOrig;
47855552b385SBrandon 
47865552b385SBrandon       if (islite) PetscCallEGADS(EGlite_getTopology, (origEdge, &geomEdgeOrig, &oclassEdgeOrig, &mtypeEdgeOrig, NULL, &NnOrig, &nobjsOrig, &nsensesEdgeOrig));
47875552b385SBrandon       else PetscCallEGADS(EG_getTopology, (origEdge, &geomEdgeOrig, &oclassEdgeOrig, &mtypeEdgeOrig, NULL, &NnOrig, &nobjsOrig, &nsensesEdgeOrig));
47885552b385SBrandon 
47895552b385SBrandon       PetscBool isSame = PETSC_FALSE;
47905552b385SBrandon       for (int jj = 0; jj < numNewEdge; ++jj) {
47915552b385SBrandon         ego newEdge = eobjsNew[jj];
47925552b385SBrandon         ego geomEdgeNew, *nobjsNew;
47935552b385SBrandon         int oclassEdgeNew, mtypeEdgeNew;
47945552b385SBrandon         int NnNew, *nsensesEdgeNew;
47955552b385SBrandon 
47965552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getTopology, (newEdge, &geomEdgeNew, &oclassEdgeNew, &mtypeEdgeNew, NULL, &NnNew, &nobjsNew, &nsensesEdgeNew));
47975552b385SBrandon         else PetscCallEGADS(EG_getTopology, (newEdge, &geomEdgeNew, &oclassEdgeNew, &mtypeEdgeNew, NULL, &NnNew, &nobjsNew, &nsensesEdgeNew));
47985552b385SBrandon 
47995552b385SBrandon         if (mtypeEdgeOrig == mtypeEdgeNew) {
48005552b385SBrandon           // Only operate if the EDGE types are the same
48015552b385SBrandon           for (int kk = 0; kk < NnNew; ++kk) {
48025552b385SBrandon             int nodeIDOrigGeom, nodeIDNewGeom;
48035552b385SBrandon             if (islite) {
48045552b385SBrandon               nodeIDOrigGeom = EGlite_indexBodyTopo(body, nobjsOrig[kk]);
48055552b385SBrandon               nodeIDNewGeom  = EGlite_indexBodyTopo(newbody, nobjsNew[kk]);
48065552b385SBrandon             } else {
48075552b385SBrandon               nodeIDOrigGeom = EG_indexBodyTopo(body, nobjsOrig[kk]);
48085552b385SBrandon               nodeIDNewGeom  = EG_indexBodyTopo(newbody, nobjsNew[kk]);
48095552b385SBrandon             }
48105552b385SBrandon 
48115552b385SBrandon             if (nodeIDNewGeom == nodeIDEquiv[nodeIDOrigGeom]) {
48125552b385SBrandon               isSame = PETSC_TRUE;
48135552b385SBrandon             } else {
48145552b385SBrandon               isSame = PETSC_FALSE;
48155552b385SBrandon               kk     = NnNew; // skip ahead because first NODE failed test and order is important
48165552b385SBrandon             }
48175552b385SBrandon           }
48185552b385SBrandon 
48195552b385SBrandon           if (isSame == PETSC_TRUE) {
48205552b385SBrandon             int edgeIDOrig, edgeIDNew;
48215552b385SBrandon             if (islite) {
48225552b385SBrandon               edgeIDOrig = EGlite_indexBodyTopo(body, origEdge);
48235552b385SBrandon               edgeIDNew  = EGlite_indexBodyTopo(newbody, newEdge);
48245552b385SBrandon             } else {
48255552b385SBrandon               edgeIDOrig = EG_indexBodyTopo(body, origEdge);
48265552b385SBrandon               edgeIDNew  = EG_indexBodyTopo(newbody, newEdge);
48275552b385SBrandon             }
48285552b385SBrandon 
48295552b385SBrandon             edgeIDEquiv[edgeIDOrig] = edgeIDNew;
48305552b385SBrandon             jj                      = numNewEdge;
48315552b385SBrandon           }
48325552b385SBrandon         }
48335552b385SBrandon       }
48345552b385SBrandon     }
48355552b385SBrandon     if (islite) {
48365552b385SBrandon       EGlite_free(eobjsOrig);
48375552b385SBrandon       EGlite_free(eobjsNew);
48385552b385SBrandon     } else {
48395552b385SBrandon       EG_free(eobjsOrig);
48405552b385SBrandon       EG_free(eobjsNew);
48415552b385SBrandon     }
48425552b385SBrandon   }
48435552b385SBrandon   if (islite) {
48445552b385SBrandon     EGlite_free(fobjs);
48455552b385SBrandon     EGlite_free(nfobjs);
48465552b385SBrandon   } else {
48475552b385SBrandon     EG_free(fobjs);
48485552b385SBrandon     EG_free(nfobjs);
48495552b385SBrandon   }
48505552b385SBrandon 
48515552b385SBrandon   // Modify labels to point to the IDs on the new Geometry
48525552b385SBrandon   IS isNodeID, isEdgeID;
48535552b385SBrandon 
48545552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
48555552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
48565552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
48575552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
48585552b385SBrandon 
48595552b385SBrandon   PetscCall(ISCreateGeneral(comm, totalNumNode + 1, nodeIDEquiv, PETSC_COPY_VALUES, &isNodeID));
48605552b385SBrandon   PetscCall(ISCreateGeneral(comm, totalNumEdge + 1, edgeIDEquiv, PETSC_COPY_VALUES, &isEdgeID));
48615552b385SBrandon   /* Do not perform check. Np may != Nv due to Degenerate Geometry which is not stored in labels.               */
48625552b385SBrandon   /* We do not know in advance which IDs have been omitted. This may also change due to geometry modifications. */
48635552b385SBrandon   PetscCall(DMLabelRewriteValues(vertexLabel, isNodeID));
48645552b385SBrandon   PetscCall(DMLabelRewriteValues(edgeLabel, isEdgeID));
48655552b385SBrandon   PetscCall(ISDestroy(&isNodeID));
48665552b385SBrandon   PetscCall(ISDestroy(&isEdgeID));
48675552b385SBrandon 
48685552b385SBrandon   // Attempt to point to the new geometry
48695552b385SBrandon   PetscCallEGADS(EG_deleteObject, (model));
48705552b385SBrandon   PetscCall(PetscContainerSetPointer(modelObj, newmodel));
48715552b385SBrandon 
48725552b385SBrandon   // save updated model to file
48735552b385SBrandon   if (saveGeom == PETSC_TRUE && stpName != NULL) PetscCall(EG_saveModel(newmodel, stpName));
48745552b385SBrandon 
48755552b385SBrandon   // Inflate Mesh to EGADS Model
48765552b385SBrandon   if (autoInflate == PETSC_TRUE) PetscCall(DMPlexInflateToGeomModel(dm, PETSC_TRUE));
48775552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
48785552b385SBrandon #else
48795552b385SBrandon   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
48805552b385SBrandon #endif
48815552b385SBrandon }
48825552b385SBrandon 
48835552b385SBrandon /*@C
48845552b385SBrandon   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.
48855552b385SBrandon 
48865552b385SBrandon   Collective
48875552b385SBrandon 
48885552b385SBrandon   Input Parameter:
48895552b385SBrandon . dm - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
48905552b385SBrandon 
48915552b385SBrandon   Level: intermediate
48925552b385SBrandon 
48935552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`
48945552b385SBrandon @*/
DMPlexGetGeomModelTUV(DM dm)4895ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelTUV(DM dm) PeNS
48965552b385SBrandon {
48975552b385SBrandon #if defined(PETSC_HAVE_EGADS)
48985552b385SBrandon   /* EGADS Variables */
48995552b385SBrandon   ego    model, geom, body, face, edge;
49005552b385SBrandon   ego   *bodies;
49015552b385SBrandon   int    Nb, oclass, mtype, *senses;
49025552b385SBrandon   double result[4];
49035552b385SBrandon   /* PETSc Variables */
49045552b385SBrandon   DM             cdm;
49055552b385SBrandon   PetscContainer modelObj;
49065552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
49075552b385SBrandon   Vec            coordinates;
49085552b385SBrandon   PetscScalar   *coords;
49095552b385SBrandon   PetscInt       bodyID, faceID, edgeID, vertexID;
49105552b385SBrandon   PetscInt       cdim, vStart, vEnd, v;
49115552b385SBrandon   PetscBool      islite = PETSC_FALSE;
49125552b385SBrandon #endif
49135552b385SBrandon 
49145552b385SBrandon   PetscFunctionBegin;
49155552b385SBrandon #if defined(PETSC_HAVE_EGADS)
49165552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
49175552b385SBrandon   if (!modelObj) {
49185552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
49195552b385SBrandon     islite = PETSC_TRUE;
49205552b385SBrandon   }
4921b6555650SPierre Jolivet   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
49225552b385SBrandon 
49235552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &cdim));
49245552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
49255552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
49265552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
49275552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
49285552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
49295552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
49305552b385SBrandon 
49312a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
49325552b385SBrandon 
49335552b385SBrandon   if (islite) PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
49345552b385SBrandon   else PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
49355552b385SBrandon 
49365552b385SBrandon   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
49375552b385SBrandon   PetscCall(VecGetArrayWrite(coordinates, &coords));
49385552b385SBrandon 
49395552b385SBrandon   // Define t, u, v arrays to be stored in a PetscContainer after populated
49405552b385SBrandon   PetscScalar *t_point, *u_point, *v_point;
49415552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &t_point));
49425552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &u_point));
49435552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &v_point));
49445552b385SBrandon 
49455552b385SBrandon   for (v = vStart; v < vEnd; ++v) {
49465552b385SBrandon     PetscScalar *vcoords;
49475552b385SBrandon 
49485552b385SBrandon     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
49495552b385SBrandon     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
49505552b385SBrandon     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
49515552b385SBrandon     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
49525552b385SBrandon 
49535552b385SBrandon     // TODO Figure out why this is unknown sometimes
49545552b385SBrandon     if (bodyID < 0 && Nb == 1) bodyID = 0;
49555552b385SBrandon     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);
4956c1cad2e7SMatthew G. Knepley     body = bodies[bodyID];
4957c1cad2e7SMatthew G. Knepley 
49589566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
4959c1cad2e7SMatthew G. Knepley     if (edgeID > 0) {
4960c1cad2e7SMatthew G. Knepley       /* Snap to EDGE at nearest location */
4961c1cad2e7SMatthew G. Knepley       double params[1];
49625552b385SBrandon 
49635552b385SBrandon       if (islite) {
49645552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
49655552b385SBrandon         PetscCall(EGlite_invEvaluate(edge, vcoords, params, result));
49665552b385SBrandon       } // Get (t) of nearest point on EDGE
49675552b385SBrandon       else {
49689566063dSJacob Faibussowitsch         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
49695552b385SBrandon         PetscCall(EG_invEvaluate(edge, vcoords, params, result));
49705552b385SBrandon       } // Get (t) of nearest point on EDGE
49715552b385SBrandon 
49725552b385SBrandon       t_point[v - vStart] = params[0];
49735552b385SBrandon       u_point[v - vStart] = 0.0;
49745552b385SBrandon       v_point[v - vStart] = 0.0;
4975c1cad2e7SMatthew G. Knepley     } else if (faceID > 0) {
4976c1cad2e7SMatthew G. Knepley       /* Snap to FACE at nearest location */
4977c1cad2e7SMatthew G. Knepley       double params[2];
49785552b385SBrandon 
49795552b385SBrandon       if (islite) {
49805552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
49815552b385SBrandon         PetscCall(EGlite_invEvaluate(face, vcoords, params, result));
49825552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
49835552b385SBrandon       else {
49849566063dSJacob Faibussowitsch         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
49855552b385SBrandon         PetscCall(EG_invEvaluate(face, vcoords, params, result));
49865552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
49875552b385SBrandon 
49885552b385SBrandon       t_point[v - vStart] = 0.0;
49895552b385SBrandon       u_point[v - vStart] = params[0];
49905552b385SBrandon       v_point[v - vStart] = params[1];
49915552b385SBrandon     } else {
49925552b385SBrandon       t_point[v - vStart] = 0.0;
49935552b385SBrandon       u_point[v - vStart] = 0.0;
49945552b385SBrandon       v_point[v - vStart] = 0.0;
49955552b385SBrandon     }
49965552b385SBrandon   }
49975552b385SBrandon   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
49985552b385SBrandon   /* Clear out global coordinates */
49995552b385SBrandon   PetscCall(VecDestroy(&dm->coordinates[0].x));
50005552b385SBrandon 
50015552b385SBrandon   /* Store in PetscContainters */
50025552b385SBrandon   {
50035552b385SBrandon     PetscContainer t_pointObj, u_pointObj, v_pointObj;
50045552b385SBrandon 
50055552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Edge t Parameter", (PetscObject *)&t_pointObj));
50065552b385SBrandon     if (!t_pointObj) {
50075552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &t_pointObj));
50085552b385SBrandon       PetscCall(PetscContainerSetPointer(t_pointObj, t_point));
50095552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Edge t Parameter", (PetscObject)t_pointObj));
50105552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(t_pointObj, PetscCtxDestroyDefault));
50115552b385SBrandon       PetscCall(PetscContainerDestroy(&t_pointObj));
50125552b385SBrandon     } else {
50135552b385SBrandon       void *old;
50145552b385SBrandon 
50155552b385SBrandon       PetscCall(PetscContainerGetPointer(t_pointObj, &old));
50165552b385SBrandon       PetscCall(PetscFree(old));
50175552b385SBrandon       PetscCall(PetscContainerSetPointer(t_pointObj, t_point));
50185552b385SBrandon     }
50195552b385SBrandon 
50205552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face u Parameter", (PetscObject *)&u_pointObj));
50215552b385SBrandon     if (!u_pointObj) {
50225552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &u_pointObj));
50235552b385SBrandon       PetscCall(PetscContainerSetPointer(u_pointObj, u_point));
50245552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Face u Parameter", (PetscObject)u_pointObj));
50255552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(u_pointObj, PetscCtxDestroyDefault));
50265552b385SBrandon       PetscCall(PetscContainerDestroy(&u_pointObj));
50275552b385SBrandon     } else {
50285552b385SBrandon       void *old;
50295552b385SBrandon 
50305552b385SBrandon       PetscCall(PetscContainerGetPointer(u_pointObj, &old));
50315552b385SBrandon       PetscCall(PetscFree(old));
50325552b385SBrandon       PetscCall(PetscContainerSetPointer(u_pointObj, u_point));
50335552b385SBrandon     }
50345552b385SBrandon 
50355552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face v Parameter", (PetscObject *)&v_pointObj));
50365552b385SBrandon     if (!v_pointObj) {
50375552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &v_pointObj));
50385552b385SBrandon       PetscCall(PetscContainerSetPointer(v_pointObj, v_point));
50395552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Face v Parameter", (PetscObject)v_pointObj));
50405552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(v_pointObj, PetscCtxDestroyDefault));
50415552b385SBrandon       PetscCall(PetscContainerDestroy(&v_pointObj));
50425552b385SBrandon     } else {
50435552b385SBrandon       void *old;
50445552b385SBrandon 
50455552b385SBrandon       PetscCall(PetscContainerGetPointer(v_pointObj, &old));
50465552b385SBrandon       PetscCall(PetscFree(old));
50475552b385SBrandon       PetscCall(PetscContainerSetPointer(v_pointObj, v_point));
50485552b385SBrandon     }
50495552b385SBrandon   }
50505552b385SBrandon #endif
50515552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
50525552b385SBrandon }
50535552b385SBrandon 
50545552b385SBrandon /*@C
50555552b385SBrandon   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().
50565552b385SBrandon 
50575552b385SBrandon   Collective
50585552b385SBrandon 
50595552b385SBrandon   Input Parameter:
50605552b385SBrandon . dm - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
50615552b385SBrandon 
50625552b385SBrandon   Level: intermediate
50635552b385SBrandon 
50645552b385SBrandon   Note:
50655552b385SBrandon   The updated DM object inflated to the associated underlying geometry. This updates the [x, y, z] coordinates of DM points associated with geometry.
50665552b385SBrandon 
50675552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`, `DMPlexGetGeomModelTUV()`
50685552b385SBrandon @*/
DMPlexInflateToGeomModelUseTUV(DM dm)5069ce78bad3SBarry Smith PetscErrorCode DMPlexInflateToGeomModelUseTUV(DM dm) PeNS
50705552b385SBrandon {
50715552b385SBrandon #if defined(PETSC_HAVE_EGADS)
50725552b385SBrandon   /* EGADS Variables */
50735552b385SBrandon   ego    model, geom, body, face, edge, vertex;
50745552b385SBrandon   ego   *bodies;
50755552b385SBrandon   int    Nb, oclass, mtype, *senses;
50765552b385SBrandon   double result[18], params[2];
50775552b385SBrandon   /* PETSc Variables */
50785552b385SBrandon   DM             cdm;
50795552b385SBrandon   PetscContainer modelObj;
50805552b385SBrandon   PetscContainer t_pointObj, u_pointObj, v_pointObj;
50815552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
50825552b385SBrandon   Vec            coordinates;
50835552b385SBrandon   PetscScalar   *coords;
50845552b385SBrandon   PetscScalar   *t_point, *u_point, *v_point;
50855552b385SBrandon   PetscInt       bodyID, faceID, edgeID, vertexID;
50865552b385SBrandon   PetscInt       cdim, d, vStart, vEnd, v;
50875552b385SBrandon   PetscBool      islite = PETSC_FALSE;
50885552b385SBrandon #endif
50895552b385SBrandon 
50905552b385SBrandon   PetscFunctionBegin;
50915552b385SBrandon #if defined(PETSC_HAVE_EGADS)
50925552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
50935552b385SBrandon   if (!modelObj) {
50945552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
50955552b385SBrandon     islite = PETSC_TRUE;
50965552b385SBrandon   }
50975552b385SBrandon 
50985552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Edge t Parameter", (PetscObject *)&t_pointObj));
50995552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face u Parameter", (PetscObject *)&u_pointObj));
51005552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face v Parameter", (PetscObject *)&v_pointObj));
51015552b385SBrandon 
51025552b385SBrandon   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
51035552b385SBrandon   if (!t_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
51045552b385SBrandon   if (!u_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
51055552b385SBrandon   if (!v_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
51065552b385SBrandon 
51075552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &cdim));
51085552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
51095552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
51105552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
51115552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
51125552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
51135552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
51145552b385SBrandon 
51152a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(t_pointObj, &t_point));
51162a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(u_pointObj, &u_point));
51172a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(v_pointObj, &v_point));
51185552b385SBrandon 
51192a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
51205552b385SBrandon 
51215552b385SBrandon   if (islite) {
51225552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
51235552b385SBrandon   } else {
51245552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
51255552b385SBrandon   }
51265552b385SBrandon 
51275552b385SBrandon   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
51285552b385SBrandon   PetscCall(VecGetArrayWrite(coordinates, &coords));
51295552b385SBrandon 
51305552b385SBrandon   for (v = vStart; v < vEnd; ++v) {
51315552b385SBrandon     PetscScalar *vcoords;
51325552b385SBrandon 
51335552b385SBrandon     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
51345552b385SBrandon     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
51355552b385SBrandon     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
51365552b385SBrandon     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
51375552b385SBrandon 
51385552b385SBrandon     // TODO Figure out why this is unknown sometimes
51395552b385SBrandon     if (bodyID < 0 && Nb == 1) bodyID = 0;
51405552b385SBrandon     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);
51415552b385SBrandon     body = bodies[bodyID];
51425552b385SBrandon 
51435552b385SBrandon     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
51445552b385SBrandon     if (vertexID > 0) {
51455552b385SBrandon       /* Snap to Vertices */
51465552b385SBrandon       if (islite) {
51475552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, NODE, vertexID, &vertex));
51485552b385SBrandon         PetscCall(EGlite_evaluate(vertex, NULL, result));
51495552b385SBrandon       } else {
51505552b385SBrandon         PetscCall(EG_objectBodyTopo(body, NODE, vertexID, &vertex));
51515552b385SBrandon         PetscCall(EG_evaluate(vertex, NULL, result));
51525552b385SBrandon       }
51535552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
51545552b385SBrandon     } else if (edgeID > 0) {
51555552b385SBrandon       /* Snap to EDGE */
51565552b385SBrandon       params[0] = t_point[v - vStart];
51575552b385SBrandon       if (islite) {
51585552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
51595552b385SBrandon         PetscCall(EGlite_evaluate(edge, params, result));
51605552b385SBrandon       } else {
51615552b385SBrandon         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
51625552b385SBrandon         PetscCall(EG_evaluate(edge, params, result));
51635552b385SBrandon       }
51645552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
51655552b385SBrandon     } else if (faceID > 0) {
51665552b385SBrandon       /* Snap to FACE */
51675552b385SBrandon       params[0] = u_point[v - vStart];
51685552b385SBrandon       params[1] = v_point[v - vStart];
51695552b385SBrandon       if (islite) {
51705552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
51715552b385SBrandon         PetscCall(EGlite_evaluate(face, params, result));
51725552b385SBrandon       } else {
51735552b385SBrandon         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
51745552b385SBrandon         PetscCall(EG_evaluate(face, params, result));
51755552b385SBrandon       }
5176c1cad2e7SMatthew G. Knepley       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
5177c1cad2e7SMatthew G. Knepley     }
5178c1cad2e7SMatthew G. Knepley   }
51799566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5180c1cad2e7SMatthew G. Knepley   /* Clear out global coordinates */
51816858538eSMatthew G. Knepley   PetscCall(VecDestroy(&dm->coordinates[0].x));
5182c1cad2e7SMatthew G. Knepley #endif
51833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5184c1cad2e7SMatthew G. Knepley }
5185c1cad2e7SMatthew G. Knepley 
5186cc4c1da9SBarry Smith /*@
51875552b385SBrandon   DMPlexInflateToGeomModel - Wrapper function allowing two methods for inflating refined meshes to the underlying geometric domain.
51887bee2925SMatthew Knepley 
51897bee2925SMatthew Knepley   Collective
51907bee2925SMatthew Knepley 
51917bee2925SMatthew Knepley   Input Parameters:
51925552b385SBrandon + dm     - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
51935552b385SBrandon - useTUV - PetscBool indicating if the user would like to inflate the DMPlex to the underlying geometry
51945552b385SBrandon            using (t) for nodes on EDGEs and (u, v) for nodes on FACEs or using the nodes (x, y, z) coordinates
51955552b385SBrandon            and shortest distance routine.
51965552b385SBrandon             If useTUV = PETSC_TRUE, use the (t) or (u, v) parameters to inflate the DMPlex to the CAD geometry.
51975552b385SBrandon             If useTUV = PETSC_FALSE, use the nodes (x, y, z) coordinates and the shortest disctance routine.
51985552b385SBrandon 
51995552b385SBrandon   Notes:
52005552b385SBrandon   DM with nodal coordinates modified so that they lie on the EDGEs and FACEs of the underlying geometry.
52015552b385SBrandon 
52025552b385SBrandon   (t) and (u, v) parameters for all DMPlex nodes on EDGEs and FACEs are stored in arrays within PetscContainers attached to the DM.
52035552b385SBrandon   The containers have names "Point - Edge t Parameter", "Point - Face u Parameter", and "Point - Face v Parameter".
52045552b385SBrandon   The arrays are organized by Point 0-based ID (i.e. [v-vstart] as defined in the DMPlex.
52055552b385SBrandon 
52065552b385SBrandon   Level: intermediate
52075552b385SBrandon 
52085552b385SBrandon .seealso: `DMPlexGetGeomModelTUV()`, `DMPlexInflateToGeomModelUseTUV()`, `DMPlexInflateToGeomModelUseXYZ()`
52095552b385SBrandon @*/
DMPlexInflateToGeomModel(DM dm,PetscBool useTUV)5210ce78bad3SBarry Smith PetscErrorCode DMPlexInflateToGeomModel(DM dm, PetscBool useTUV) PeNS
52115552b385SBrandon {
52125552b385SBrandon   PetscFunctionBeginHot;
52135552b385SBrandon   if (useTUV) {
52145552b385SBrandon     PetscCall(DMPlexGetGeomModelTUV(dm));
52155552b385SBrandon     PetscCall(DMPlexInflateToGeomModelUseTUV(dm));
52165552b385SBrandon   } else {
52175552b385SBrandon     PetscCall(DMPlexInflateToGeomModelUseXYZ(dm));
52185552b385SBrandon   }
52195552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
52205552b385SBrandon }
52215552b385SBrandon 
52225552b385SBrandon #ifdef PETSC_HAVE_EGADS
52235552b385SBrandon /*@C
5224bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodies - Returns an array of `PetscGeom` BODY objects attached to the referenced geometric model entity as well as the number of BODYs.
52255552b385SBrandon 
52265552b385SBrandon   Collective
52275552b385SBrandon 
52285552b385SBrandon   Input Parameter:
52295552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
52305552b385SBrandon 
52315552b385SBrandon   Output Parameters:
52325552b385SBrandon + bodies    - Array of PetscGeom BODY objects referenced by the geometric model.
52335552b385SBrandon - numBodies - Number of BODYs referenced by the geometric model. Also the size of **bodies array.
52345552b385SBrandon 
52355552b385SBrandon   Level: intermediate
52365552b385SBrandon 
52375552b385SBrandon .seealso:
52385552b385SBrandon @*/
DMPlexGetGeomModelBodies(DM dm,PetscGeom ** bodies,PetscInt * numBodies)5239ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodies(DM dm, PetscGeom **bodies, PetscInt *numBodies) PeNS
52405552b385SBrandon {
52415552b385SBrandon   PetscFunctionBeginHot;
52425552b385SBrandon   PetscContainer modelObj;
52435552b385SBrandon   PetscBool      islite = PETSC_FALSE;
52445552b385SBrandon   ego            model, geom;
52455552b385SBrandon   int            oclass, mtype;
52465552b385SBrandon   int           *senses;
52475552b385SBrandon 
52485552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
52495552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
52505552b385SBrandon   if (!modelObj) {
52515552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
52525552b385SBrandon     islite = PETSC_TRUE;
52535552b385SBrandon   }
52545552b385SBrandon 
52555552b385SBrandon   // Get attached EGADS or EGADSlite model (pointer)
52562a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(modelObj, &model));
52575552b385SBrandon 
52585552b385SBrandon   if (islite) {
52595552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, numBodies, bodies, &senses));
52605552b385SBrandon   } else {
52615552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, numBodies, bodies, &senses));
52625552b385SBrandon   }
52635552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
52645552b385SBrandon }
52655552b385SBrandon 
52665552b385SBrandon /*@C
5267bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyShells - Returns an array of `PetscGeom` SHELL objects attached to the referenced BODY geometric entity as well as the number of SHELLs.
52685552b385SBrandon 
52695552b385SBrandon   Collective
52705552b385SBrandon 
52715552b385SBrandon   Input Parameters:
52725552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
52735552b385SBrandon - body - PetscGeom BODY object containing the SHELL objects of interest.
52745552b385SBrandon 
52755552b385SBrandon   Output Parameters:
52765552b385SBrandon + shells    - Array of PetscGeom SHELL objects referenced by the PetscGeom BODY object
52775552b385SBrandon - numShells - Number of SHELLs referenced by the PetscGeom BODY object. Also the size of **shells array.
52785552b385SBrandon 
52795552b385SBrandon   Level: intermediate
52805552b385SBrandon 
52815552b385SBrandon .seealso:
52825552b385SBrandon @*/
DMPlexGetGeomModelBodyShells(DM dm,PetscGeom body,PetscGeom ** shells,PetscInt * numShells)5283ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyShells(DM dm, PetscGeom body, PetscGeom **shells, PetscInt *numShells) PeNS
52845552b385SBrandon {
52855552b385SBrandon   PetscFunctionBeginHot;
52865552b385SBrandon   #ifdef PETSC_HAVE_EGADS
52875552b385SBrandon   PetscContainer modelObj;
52885552b385SBrandon   PetscBool      islite = PETSC_FALSE;
52895552b385SBrandon 
52905552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
52915552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
52925552b385SBrandon   if (!modelObj) {
52935552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
52945552b385SBrandon     islite = PETSC_TRUE;
52955552b385SBrandon   }
52965552b385SBrandon 
52975552b385SBrandon   if (islite) {
52985552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, SHELL, numShells, shells));
52995552b385SBrandon   } else {
53005552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, SHELL, numShells, shells));
53015552b385SBrandon   }
53025552b385SBrandon   #endif
53035552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
53045552b385SBrandon }
53055552b385SBrandon 
53065552b385SBrandon /*@C
5307bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyFaces - Returns an array of `PetscGeom` FACE objects attached to the referenced BODY geometric entity as well as the number of FACEs.
53085552b385SBrandon 
53095552b385SBrandon   Collective
53105552b385SBrandon 
53115552b385SBrandon   Input Parameters:
53125552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
53135552b385SBrandon - body - PetscGeom BODY object containing the FACE objects of interest.
53145552b385SBrandon 
53155552b385SBrandon   Output Parameters:
53165552b385SBrandon + faces    - Array of PetscGeom FACE objects referenced by the PetscGeom BODY object
53175552b385SBrandon - numFaces - Number of FACEs referenced by the PetscGeom BODY object. Also the size of **faces array.
53185552b385SBrandon 
53195552b385SBrandon   Level: intermediate
53205552b385SBrandon 
53215552b385SBrandon .seealso:
53225552b385SBrandon @*/
DMPlexGetGeomModelBodyFaces(DM dm,PetscGeom body,PetscGeom ** faces,PetscInt * numFaces)5323ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyFaces(DM dm, PetscGeom body, PetscGeom **faces, PetscInt *numFaces) PeNS
53245552b385SBrandon {
53255552b385SBrandon   PetscFunctionBeginHot;
53265552b385SBrandon   #ifdef PETSC_HAVE_EGADS
53275552b385SBrandon   PetscContainer modelObj;
53285552b385SBrandon   PetscBool      islite = PETSC_FALSE;
53295552b385SBrandon 
53305552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
53315552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
53325552b385SBrandon   if (!modelObj) {
53335552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
53345552b385SBrandon     islite = PETSC_TRUE;
53355552b385SBrandon   }
53365552b385SBrandon 
53375552b385SBrandon   if (islite) {
53385552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, numFaces, faces));
53395552b385SBrandon   } else {
53405552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, numFaces, faces));
53415552b385SBrandon   }
53425552b385SBrandon   #endif
53435552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
53445552b385SBrandon }
53455552b385SBrandon 
53465552b385SBrandon /*@C
5347bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyLoops - Returns an array of `PetscGeom` Loop objects attached to the referenced BODY geometric entity as well as the number of LOOPs.
53485552b385SBrandon 
53495552b385SBrandon   Collective
53505552b385SBrandon 
53515552b385SBrandon   Input Parameters:
53525552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
53535552b385SBrandon - body - PetscGeom BODY object containing the LOOP objects of interest.
53545552b385SBrandon 
53555552b385SBrandon   Output Parameters:
53565552b385SBrandon + loops    - Array of PetscGeom FACE objects referenced by the PetscGeom SHELL object
53575552b385SBrandon - numLoops - Number of LOOPs referenced by the PetscGeom BODY object. Also the size of **loops array.
53585552b385SBrandon 
53595552b385SBrandon   Level: intermediate
53605552b385SBrandon 
53615552b385SBrandon .seealso:
53625552b385SBrandon @*/
DMPlexGetGeomModelBodyLoops(DM dm,PetscGeom body,PetscGeom ** loops,PetscInt * numLoops)5363ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyLoops(DM dm, PetscGeom body, PetscGeom **loops, PetscInt *numLoops) PeNS
53645552b385SBrandon {
53655552b385SBrandon   PetscFunctionBeginHot;
53665552b385SBrandon   #ifdef PETSC_HAVE_EGADS
53675552b385SBrandon   PetscContainer modelObj;
53685552b385SBrandon   PetscBool      islite = PETSC_FALSE;
53695552b385SBrandon 
53705552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
53715552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
53725552b385SBrandon   if (!modelObj) {
53735552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
53745552b385SBrandon     islite = PETSC_TRUE;
53755552b385SBrandon   }
53765552b385SBrandon 
53775552b385SBrandon   if (islite) {
53785552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, numLoops, loops));
53795552b385SBrandon   } else {
53805552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, LOOP, numLoops, loops));
53815552b385SBrandon   }
53825552b385SBrandon   #endif
53835552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
53845552b385SBrandon }
53855552b385SBrandon 
53865552b385SBrandon /*@C
5387bfe80ac4SPierre Jolivet   DMPlexGetGeomModelShellFaces - Returns an array of `PetscGeom` FACE objects attached to the referenced SHELL geometric entity as well as the number of FACEs.
53885552b385SBrandon 
53895552b385SBrandon   Collective
53905552b385SBrandon 
53915552b385SBrandon   Input Parameters:
53925552b385SBrandon + dm    - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
53935552b385SBrandon . body  - PetscGeom BODY object containing the FACE objects of interest.
53945552b385SBrandon - shell - PetscGeom SHELL object with FACEs of interest.
53955552b385SBrandon 
53965552b385SBrandon   Output Parameters:
53975552b385SBrandon + faces    - Array of PetscGeom FACE objects referenced by the PetscGeom SHELL object
53985552b385SBrandon - numFaces - Number of FACEs referenced by the PetscGeom SHELL object. Also the size of **faces array.
53995552b385SBrandon 
54005552b385SBrandon   Level: intermediate
54015552b385SBrandon 
54025552b385SBrandon .seealso:
54035552b385SBrandon @*/
DMPlexGetGeomModelShellFaces(DM dm,PetscGeom body,PetscGeom shell,PetscGeom ** faces,PetscInt * numFaces)5404ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelShellFaces(DM dm, PetscGeom body, PetscGeom shell, PetscGeom **faces, PetscInt *numFaces) PeNS
54055552b385SBrandon {
54065552b385SBrandon   PetscFunctionBeginHot;
54075552b385SBrandon   #ifdef PETSC_HAVE_EGADS
54085552b385SBrandon   PetscContainer modelObj;
54095552b385SBrandon   PetscBool      islite = PETSC_FALSE;
54105552b385SBrandon 
54115552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
54125552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
54135552b385SBrandon   if (!modelObj) {
54145552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
54155552b385SBrandon     islite = PETSC_TRUE;
54165552b385SBrandon   }
54175552b385SBrandon 
54185552b385SBrandon   if (islite) {
54195552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, shell, FACE, numFaces, faces));
54205552b385SBrandon   } else {
54215552b385SBrandon     PetscCall(EG_getBodyTopos(body, shell, FACE, numFaces, faces));
54225552b385SBrandon   }
54235552b385SBrandon   #endif
54245552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
54255552b385SBrandon }
54265552b385SBrandon 
54275552b385SBrandon /*@C
5428bfe80ac4SPierre Jolivet   DMPlexGetGeomModelFaceLoops - Returns an array of `PetscGeom` LOOP objects attached to the referenced FACE geometric entity as well as the number of LOOPs.
54295552b385SBrandon 
54305552b385SBrandon   Collective
54315552b385SBrandon 
54325552b385SBrandon   Input Parameters:
54335552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
54345552b385SBrandon . body - PetscGeom BODY object containing the LOOP objects of interest.
54355552b385SBrandon - face - PetscGeom FACE object with LOOPs of interest.
54365552b385SBrandon 
54375552b385SBrandon   Output Parameters:
54385552b385SBrandon + loops    - Array of PetscGeom LOOP objects referenced by the PetscGeom FACE object
54395552b385SBrandon - numLoops - Number of LOOPs referenced by the PetscGeom FACE object. Also the size of **loops array.
54405552b385SBrandon 
54415552b385SBrandon   Level: intermediate
54425552b385SBrandon 
54435552b385SBrandon .seealso:
54445552b385SBrandon @*/
DMPlexGetGeomModelFaceLoops(DM dm,PetscGeom body,PetscGeom face,PetscGeom ** loops,PetscInt * numLoops)5445ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelFaceLoops(DM dm, PetscGeom body, PetscGeom face, PetscGeom **loops, PetscInt *numLoops) PeNS
54465552b385SBrandon {
54475552b385SBrandon   PetscFunctionBeginHot;
54485552b385SBrandon   #ifdef PETSC_HAVE_EGADS
54495552b385SBrandon   PetscContainer modelObj;
54505552b385SBrandon   PetscBool      islite = PETSC_FALSE;
54515552b385SBrandon 
54525552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
54535552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
54545552b385SBrandon   if (!modelObj) {
54555552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
54565552b385SBrandon     islite = PETSC_TRUE;
54575552b385SBrandon   }
54585552b385SBrandon 
54595552b385SBrandon   if (islite) {
54605552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, face, LOOP, numLoops, loops));
54615552b385SBrandon   } else {
54625552b385SBrandon     PetscCall(EG_getBodyTopos(body, face, LOOP, numLoops, loops));
54635552b385SBrandon   }
54645552b385SBrandon   #endif
54655552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
54665552b385SBrandon }
54675552b385SBrandon 
54685552b385SBrandon /*@C
5469bfe80ac4SPierre Jolivet   DMPlexGetGeomModelFaceEdges - Returns an array of `PetscGeom` EDGE objects attached to the referenced FACE geometric entity as well as the number of EDGEs.
54705552b385SBrandon 
54715552b385SBrandon   Collective
54725552b385SBrandon 
54735552b385SBrandon   Input Parameters:
54745552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
54755552b385SBrandon . body - PetscGeom Body object containing the EDGE objects of interest.
54765552b385SBrandon - face - PetscGeom FACE object with EDGEs of interest.
54775552b385SBrandon 
54785552b385SBrandon   Output Parameters:
54795552b385SBrandon + edges    - Array of PetscGeom EDGE objects referenced by the PetscGeom FACE object
54805552b385SBrandon - numEdges - Number of EDGEs referenced by the PetscGeom FACE object. Also the size of **edges array.
54815552b385SBrandon 
54825552b385SBrandon   Level: intermediate
54835552b385SBrandon 
54845552b385SBrandon .seealso:
54855552b385SBrandon @*/
DMPlexGetGeomModelFaceEdges(DM dm,PetscGeom body,PetscGeom face,PetscGeom ** edges,PetscInt * numEdges)5486ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelFaceEdges(DM dm, PetscGeom body, PetscGeom face, PetscGeom **edges, PetscInt *numEdges) PeNS
54875552b385SBrandon {
54885552b385SBrandon   PetscFunctionBeginHot;
54895552b385SBrandon   #ifdef PETSC_HAVE_EGADS
54905552b385SBrandon   PetscContainer modelObj;
54915552b385SBrandon   PetscBool      islite = PETSC_FALSE;
54925552b385SBrandon 
54935552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
54945552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
54955552b385SBrandon   if (!modelObj) {
54965552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
54975552b385SBrandon     islite = PETSC_TRUE;
54985552b385SBrandon   }
54995552b385SBrandon 
55005552b385SBrandon   if (islite) {
55015552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, face, EDGE, numEdges, edges));
55025552b385SBrandon   } else {
55035552b385SBrandon     PetscCall(EG_getBodyTopos(body, face, EDGE, numEdges, edges));
55045552b385SBrandon   }
55055552b385SBrandon   #endif
55065552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
55075552b385SBrandon }
55085552b385SBrandon 
55095552b385SBrandon /*@C
5510bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyEdges - Returns an array of `PetscGeom` EDGE objects attached to the referenced BODY geometric entity as well as the number of EDGEs.
55115552b385SBrandon 
55125552b385SBrandon   Collective
55135552b385SBrandon 
55145552b385SBrandon   Input Parameters:
55155552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
55165552b385SBrandon - body - PetscGeom body object of interest.
55175552b385SBrandon 
55185552b385SBrandon   Output Parameters:
55195552b385SBrandon + edges    - Array of PetscGeom EDGE objects referenced by the PetscGeom BODY object
55205552b385SBrandon - numEdges - Number of EDGEs referenced by the PetscGeom BODY object. Also the size of **edges array.
55215552b385SBrandon 
55225552b385SBrandon   Level: intermediate
55235552b385SBrandon 
55245552b385SBrandon .seealso:
55255552b385SBrandon @*/
DMPlexGetGeomModelBodyEdges(DM dm,PetscGeom body,PetscGeom ** edges,PetscInt * numEdges)5526ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyEdges(DM dm, PetscGeom body, PetscGeom **edges, PetscInt *numEdges) PeNS
55275552b385SBrandon {
55285552b385SBrandon   PetscFunctionBeginHot;
55295552b385SBrandon   #ifdef PETSC_HAVE_EGADS
55305552b385SBrandon   PetscContainer modelObj;
55315552b385SBrandon   PetscBool      islite = PETSC_FALSE;
55325552b385SBrandon 
55335552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
55345552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
55355552b385SBrandon   if (!modelObj) {
55365552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
55375552b385SBrandon     islite = PETSC_TRUE;
55385552b385SBrandon   }
55395552b385SBrandon 
55405552b385SBrandon   if (islite) {
55415552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, numEdges, edges));
55425552b385SBrandon   } else {
55435552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, EDGE, numEdges, edges));
55445552b385SBrandon   }
55455552b385SBrandon   #endif
55465552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
55475552b385SBrandon }
55485552b385SBrandon 
55495552b385SBrandon /*@C
5550bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyNodes - Returns an array of `PetscGeom` NODE objects attached to the referenced BODY geometric entity as well as the number of NODES.
55515552b385SBrandon 
55525552b385SBrandon   Collective
55535552b385SBrandon 
55545552b385SBrandon   Input Parameters:
55555552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
55565552b385SBrandon - body - PetscGeom body object of interest.
55575552b385SBrandon 
55585552b385SBrandon   Output Parameters:
55595552b385SBrandon + nodes    - Array of PetscGeom NODE objects referenced by the PetscGeom BODY object
55605552b385SBrandon - numNodes - Number of NODEs referenced by the PetscGeom BODY object. Also the size of **nodes array.
55615552b385SBrandon 
55625552b385SBrandon   Level: intermediate
55635552b385SBrandon 
55645552b385SBrandon .seealso:
55655552b385SBrandon @*/
DMPlexGetGeomModelBodyNodes(DM dm,PetscGeom body,PetscGeom ** nodes,PetscInt * numNodes)5566ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyNodes(DM dm, PetscGeom body, PetscGeom **nodes, PetscInt *numNodes) PeNS
55675552b385SBrandon {
55685552b385SBrandon   PetscFunctionBeginHot;
55695552b385SBrandon   #ifdef PETSC_HAVE_EGADS
55705552b385SBrandon   PetscContainer modelObj;
55715552b385SBrandon   PetscBool      islite = PETSC_FALSE;
55725552b385SBrandon 
55735552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
55745552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
55755552b385SBrandon   if (!modelObj) {
55765552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
55775552b385SBrandon     islite = PETSC_TRUE;
55785552b385SBrandon   }
55795552b385SBrandon 
55805552b385SBrandon   if (islite) {
55815552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, NODE, numNodes, nodes));
55825552b385SBrandon   } else {
55835552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, NODE, numNodes, nodes));
55845552b385SBrandon   }
55855552b385SBrandon   #endif
55865552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
55875552b385SBrandon }
55885552b385SBrandon 
55895552b385SBrandon /*@C
5590bfe80ac4SPierre Jolivet   DMPlexGetGeomModelEdgeNodes - Returns an array of `PetscGeom` NODE objects attached to the referenced EDGE geometric entity as well as the number of NODES.
55915552b385SBrandon 
55925552b385SBrandon   Collective
55935552b385SBrandon 
55945552b385SBrandon   Input Parameters:
55955552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
55965552b385SBrandon . body - PetscGeom body object containing the EDGE object of interest.
55975552b385SBrandon - edge - PetscGeom EDGE object with NODEs of interest.
55985552b385SBrandon 
55995552b385SBrandon   Output Parameters:
56005552b385SBrandon + nodes    - Array of PetscGeom NODE objects referenced by the PetscGeom EDGE object
56015552b385SBrandon - numNodes - Number of Nodes referenced by the PetscGeom EDGE object. Also the size of **nodes array.
56025552b385SBrandon 
56035552b385SBrandon   Level: intermediate
56045552b385SBrandon 
56055552b385SBrandon .seealso:
56065552b385SBrandon @*/
DMPlexGetGeomModelEdgeNodes(DM dm,PetscGeom body,PetscGeom edge,PetscGeom ** nodes,PetscInt * numNodes)5607ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelEdgeNodes(DM dm, PetscGeom body, PetscGeom edge, PetscGeom **nodes, PetscInt *numNodes) PeNS
56085552b385SBrandon {
56095552b385SBrandon   PetscFunctionBeginHot;
56105552b385SBrandon   #ifdef PETSC_HAVE_EGADS
56115552b385SBrandon   PetscContainer modelObj;
56125552b385SBrandon   PetscBool      islite = PETSC_FALSE;
56135552b385SBrandon 
56145552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
56155552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
56165552b385SBrandon   if (!modelObj) {
56175552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
56185552b385SBrandon     islite = PETSC_TRUE;
56195552b385SBrandon   }
56205552b385SBrandon 
56215552b385SBrandon   if (islite) {
56225552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, edge, NODE, numNodes, nodes));
56235552b385SBrandon   } else {
56245552b385SBrandon     PetscCall(EG_getBodyTopos(body, edge, NODE, numNodes, nodes));
56255552b385SBrandon   }
56265552b385SBrandon   #endif
56275552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
56285552b385SBrandon }
56295552b385SBrandon 
56305552b385SBrandon /*@C
56315552b385SBrandon   DMPlexGetGeomID - Returns ID number of the entity in the geometric (CAD) model
56325552b385SBrandon 
56335552b385SBrandon   Collective
56345552b385SBrandon 
56355552b385SBrandon   Input Parameters:
56365552b385SBrandon + dm      - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
56375552b385SBrandon . body    - PetscGeom body object containing the lower level entity the ID number is being requested.
56385552b385SBrandon - topoObj - PetscGeom SHELL, FACE, LOOP, EDGE, or NODE object for which ID number is being requested.
56397bee2925SMatthew Knepley 
56407bee2925SMatthew Knepley   Output Parameter:
56415552b385SBrandon . id - ID number of the entity
56427bee2925SMatthew Knepley 
56435552b385SBrandon   Level: intermediate
56447bee2925SMatthew Knepley 
56455552b385SBrandon .seealso:
56467bee2925SMatthew Knepley @*/
DMPlexGetGeomID(DM dm,PetscGeom body,PetscGeom topoObj,PetscInt * id)5647ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomID(DM dm, PetscGeom body, PetscGeom topoObj, PetscInt *id) PeNS
5648d71ae5a4SJacob Faibussowitsch {
56495552b385SBrandon   PetscFunctionBeginHot;
56505552b385SBrandon   #ifdef PETSC_HAVE_EGADS
56515552b385SBrandon   PetscContainer modelObj;
56525552b385SBrandon   PetscBool      islite = PETSC_FALSE;
56535552b385SBrandon   int            topoID;
56545552b385SBrandon 
56555552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
56565552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
56575552b385SBrandon   if (!modelObj) {
56585552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
56595552b385SBrandon     islite = PETSC_TRUE;
56605552b385SBrandon   }
56615552b385SBrandon 
56625552b385SBrandon   // Get Topology Object's ID
56635552b385SBrandon   if (islite) {
56645552b385SBrandon     topoID = EGlite_indexBodyTopo(body, topoObj);
56655552b385SBrandon   } else {
56665552b385SBrandon     topoID = EG_indexBodyTopo(body, topoObj);
56675552b385SBrandon   }
56685552b385SBrandon 
56695552b385SBrandon   *id = topoID;
56707bee2925SMatthew Knepley   #endif
56715552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
56725552b385SBrandon }
56735552b385SBrandon 
56745552b385SBrandon /*@C
56755552b385SBrandon   DMPlexGetGeomObject - Returns Geometry Object using the objects ID in the geometric (CAD) model
56765552b385SBrandon 
56775552b385SBrandon   Collective
56785552b385SBrandon 
56795552b385SBrandon   Input Parameters:
56805552b385SBrandon + dm       - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
56815552b385SBrandon . body     - PetscGeom body object containing the lower level entity the referenced by the ID.
56825552b385SBrandon . geomType - Keyword SHELL, FACE, LOOP, EDGE, or NODE of the geometry type for which ID number is being requested.
56835552b385SBrandon - geomID   - ID number of the geometry entity being requested.
56845552b385SBrandon 
56855552b385SBrandon   Output Parameter:
56865552b385SBrandon . geomObj - Geometry Object referenced by the ID number requested.
56875552b385SBrandon 
56885552b385SBrandon   Level: intermediate
56895552b385SBrandon 
56905552b385SBrandon .seealso:
56915552b385SBrandon @*/
DMPlexGetGeomObject(DM dm,PetscGeom body,PetscInt geomType,PetscInt geomID,PetscGeom * geomObj)5692ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomObject(DM dm, PetscGeom body, PetscInt geomType, PetscInt geomID, PetscGeom *geomObj) PeNS
56935552b385SBrandon {
56945552b385SBrandon   PetscFunctionBeginHot;
56955552b385SBrandon   #ifdef PETSC_HAVE_EGADS
56965552b385SBrandon   PetscContainer modelObj;
56975552b385SBrandon   PetscBool      islite = PETSC_FALSE;
56985552b385SBrandon 
56995552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
57005552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
57015552b385SBrandon   if (!modelObj) {
57025552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
57035552b385SBrandon     islite = PETSC_TRUE;
57045552b385SBrandon   }
57055552b385SBrandon 
57065552b385SBrandon   // Get Topology Object's ID
57075552b385SBrandon   if (islite) {
57085552b385SBrandon     PetscCall(EGlite_objectBodyTopo(body, geomType, geomID, geomObj));
57095552b385SBrandon   } else {
57105552b385SBrandon     PetscCall(EG_objectBodyTopo(body, geomType, geomID, geomObj));
57115552b385SBrandon   }
57125552b385SBrandon   #endif
57135552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
57145552b385SBrandon }
57155552b385SBrandon 
57165552b385SBrandon /*@C
57175552b385SBrandon   DMPlexGetGeomFaceNumOfControlPoints - Returns the total number of Control Points (and associated Weights) defining a FACE of a Geometry
57185552b385SBrandon 
57195552b385SBrandon   Not collective
57205552b385SBrandon 
57215552b385SBrandon   Input Parameters:
57225552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
57235552b385SBrandon - face - PetscGeom FACE object
57245552b385SBrandon 
57255552b385SBrandon   Output Parameter:
57265552b385SBrandon . numCntrlPnts - Number of Control Points (and Weights) defining the FACE
57275552b385SBrandon 
57285552b385SBrandon   Level: intermediate
57295552b385SBrandon 
57305552b385SBrandon .seealso:
57315552b385SBrandon @*/
DMPlexGetGeomFaceNumOfControlPoints(DM dm,PetscGeom face,PetscInt * numCntrlPnts)5732ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomFaceNumOfControlPoints(DM dm, PetscGeom face, PetscInt *numCntrlPnts) PeNS
57335552b385SBrandon {
57345552b385SBrandon   PetscFunctionBeginHot;
57355552b385SBrandon   #ifdef PETSC_HAVE_EGADS
57365552b385SBrandon   PetscContainer modelObj;
57375552b385SBrandon   PetscBool      islite = PETSC_FALSE;
57385552b385SBrandon   PetscGeom      geom, gRef;
57395552b385SBrandon   PetscGeom     *lobjs;
57405552b385SBrandon   int            Nl, oclass, mtype, goclass, gmtype;
57415552b385SBrandon   int           *lsenses, *gpinfo;
57425552b385SBrandon   double        *gprv;
57435552b385SBrandon 
57445552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
57455552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
57465552b385SBrandon   if (!modelObj) {
57475552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
57485552b385SBrandon     islite = PETSC_TRUE;
57495552b385SBrandon   }
57505552b385SBrandon 
57515552b385SBrandon   // Get Total Number of Control Points on FACE
57525552b385SBrandon   if (islite) {
57535552b385SBrandon     PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
57545552b385SBrandon     PetscCall(EGlite_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
57555552b385SBrandon   } else {
57565552b385SBrandon     PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
57575552b385SBrandon     PetscCall(EG_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
57585552b385SBrandon   }
57595552b385SBrandon 
57605552b385SBrandon   *numCntrlPnts = gpinfo[2] * gpinfo[5];
57615552b385SBrandon   #endif
57625552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
57635552b385SBrandon }
57645552b385SBrandon 
57655552b385SBrandon /*@C
57665552b385SBrandon   DMPlexGetGeomBodyMassProperties - Returns the Volume, Surface Area, Center of Gravity, and Inertia about the Body's Center of Gravity
57675552b385SBrandon 
57685552b385SBrandon   Not collective
57695552b385SBrandon 
57705552b385SBrandon   Input Parameters:
57715552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
57725552b385SBrandon - body - PetscGeom BODY object
57735552b385SBrandon 
57745552b385SBrandon   Output Parameters:
57755552b385SBrandon + volume           - Volume of the CAD Body attached to the DM Plex
57765552b385SBrandon . surfArea         - Surface Area of the CAD Body attached to the DM Plex
57775552b385SBrandon . centerOfGravity  - Array with the Center of Gravity coordinates of the CAD Body attached to the DM Plex [x, y, z]
57785552b385SBrandon . COGszie          - Size of centerOfGravity[] Array
57795552b385SBrandon . inertiaMatrixCOG - Array containing the Inertia about the Body's Center of Gravity [Ixx, Ixy, Ixz, Iyx, Iyy, Iyz, Izx, Izy, Izz]
57805552b385SBrandon - IMCOGsize        - Size of inertiaMatrixCOG[] Array
57815552b385SBrandon 
57825552b385SBrandon   Level: intermediate
57835552b385SBrandon 
57845552b385SBrandon .seealso:
57855552b385SBrandon @*/
DMPlexGetGeomBodyMassProperties(DM dm,PetscGeom body,PetscScalar * volume,PetscScalar * surfArea,PetscScalar ** centerOfGravity,PetscInt * COGsize,PetscScalar ** inertiaMatrixCOG,PetscInt * IMCOGsize)5786ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomBodyMassProperties(DM dm, PetscGeom body, PetscScalar *volume, PetscScalar *surfArea, PetscScalar **centerOfGravity, PetscInt *COGsize, PetscScalar **inertiaMatrixCOG, PetscInt *IMCOGsize) PeNS
57875552b385SBrandon {
57885552b385SBrandon   PetscFunctionBeginHot;
57895552b385SBrandon   #ifdef PETSC_HAVE_EGADS
57905552b385SBrandon   PetscContainer modelObj;
57915552b385SBrandon   PetscBool      islite = PETSC_FALSE;
57925552b385SBrandon   PetscScalar    geomData[14];
57935552b385SBrandon 
57945552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
57955552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
57965552b385SBrandon   if (!modelObj) {
57975552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
57985552b385SBrandon     islite = PETSC_TRUE;
57995552b385SBrandon     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");
58005552b385SBrandon   }
58015552b385SBrandon 
58025552b385SBrandon   if (islite) {
58035552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, " WARNING!! This functionality is not supported for EGADSlite files. \n"));
58045552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, " All returned values are equal to 0 \n"));
58055552b385SBrandon   } else {
58065552b385SBrandon     PetscCall(EG_getMassProperties(body, geomData));
58075552b385SBrandon   }
58085552b385SBrandon 
58095552b385SBrandon   PetscCall(PetscMalloc2(3, centerOfGravity, 9, inertiaMatrixCOG));
58105552b385SBrandon 
58115552b385SBrandon   if (!islite) {
58125552b385SBrandon     *volume   = geomData[0];
58135552b385SBrandon     *surfArea = geomData[1];
5814ac530a7eSPierre Jolivet     for (int ii = 2; ii < 5; ++ii) (*centerOfGravity)[ii - 2] = geomData[ii];
58155552b385SBrandon     *COGsize = 3;
5816ac530a7eSPierre Jolivet     for (int ii = 5; ii < 14; ++ii) (*inertiaMatrixCOG)[ii - 5] = geomData[ii];
58175552b385SBrandon     *IMCOGsize = 9;
58185552b385SBrandon   } else {
58195552b385SBrandon     *volume   = 0.;
58205552b385SBrandon     *surfArea = 0.;
5821ac530a7eSPierre Jolivet     for (int ii = 2; ii < 5; ++ii) (*centerOfGravity)[ii - 2] = 0.;
58225552b385SBrandon     *COGsize = 0;
5823ac530a7eSPierre Jolivet     for (int ii = 5; ii < 14; ++ii) (*inertiaMatrixCOG)[ii - 5] = 0.;
58245552b385SBrandon     *IMCOGsize = 0;
58255552b385SBrandon   }
58265552b385SBrandon   #endif
58275552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
58285552b385SBrandon }
58295552b385SBrandon 
DMPlexRestoreGeomBodyMassProperties(DM dm,PetscGeom body,PetscScalar * volume,PetscScalar * surfArea,PetscScalar ** centerOfGravity,PetscInt * COGsize,PetscScalar ** inertiaMatrixCOG,PetscInt * IMCOGsize)5830ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreGeomBodyMassProperties(DM dm, PetscGeom body, PetscScalar *volume, PetscScalar *surfArea, PetscScalar **centerOfGravity, PetscInt *COGsize, PetscScalar **inertiaMatrixCOG, PetscInt *IMCOGsize) PeNS
58315552b385SBrandon {
58325552b385SBrandon   PetscFunctionBegin;
58335552b385SBrandon   PetscCall(PetscFree2(*centerOfGravity, *inertiaMatrixCOG));
58345552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
58355552b385SBrandon }
58365552b385SBrandon 
58375552b385SBrandon /*@C
58385552b385SBrandon   DMPlexFreeGeomObject - Frees PetscGeom Objects
58395552b385SBrandon 
58405552b385SBrandon   Not collective
58415552b385SBrandon 
58425552b385SBrandon   Input Parameters:
58435552b385SBrandon + dm      - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
58445552b385SBrandon - geomObj - PetscGeom object
58455552b385SBrandon 
58465552b385SBrandon   Level: intermediate
58475552b385SBrandon 
58485552b385SBrandon .seealso:
58495552b385SBrandon @*/
DMPlexFreeGeomObject(DM dm,PetscGeom * geomObj)5850ce78bad3SBarry Smith PetscErrorCode DMPlexFreeGeomObject(DM dm, PetscGeom *geomObj) PeNS
58515552b385SBrandon {
58525552b385SBrandon   PetscFunctionBeginHot;
58535552b385SBrandon   #ifdef PETSC_HAVE_EGADS
58545552b385SBrandon   PetscContainer modelObj;
58555552b385SBrandon   PetscBool      islite = PETSC_FALSE;
58565552b385SBrandon 
58575552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
58585552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
58595552b385SBrandon   if (!modelObj) {
58605552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
58615552b385SBrandon     islite = PETSC_TRUE;
58625552b385SBrandon   }
58635552b385SBrandon 
58645552b385SBrandon   if (islite) {
58655552b385SBrandon     EGlite_free(geomObj);
58665552b385SBrandon   } else {
58675552b385SBrandon     EG_free(geomObj);
58685552b385SBrandon   }
58695552b385SBrandon   #endif
58705552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
58715552b385SBrandon }
58725552b385SBrandon 
58735552b385SBrandon /*@C
58745552b385SBrandon   DMPlexGetGeomCntrlPntAndWeightData - Gets Control Point and Associated Weight Data for the Geometry attached to the DMPlex
58755552b385SBrandon 
58765552b385SBrandon   Not collective
58775552b385SBrandon 
58785552b385SBrandon   Input Parameter:
58795552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
58805552b385SBrandon 
58815552b385SBrandon   Output Parameters:
58825552b385SBrandon + cpHashTable       - Hash Table containing the relationship between FACE ID and Control Point IDs.
58835552b385SBrandon . cpCoordDataLength - Length of cpCoordData Array.
58845552b385SBrandon . cpCoordData       - Array holding the Geometry Control Point Coordinate Data.
58855552b385SBrandon . maxNumEquiv       - Maximum Number of Equivalent Control Points (Control Points with the same coordinates but different IDs).
58865552b385SBrandon . 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
58875552b385SBrandon . wHashTable        - Hash Table containing the relationship between FACE ID and Control Point Weight.
58885552b385SBrandon . wDataLength       - Length of wData Array.
58895552b385SBrandon - wData             - Array holding the Weight for an associated Geometry Control Point.
58905552b385SBrandon 
58915552b385SBrandon   Note:
58925552b385SBrandon   Must Call DMPLexGeomDataAndGrads() before calling this function.
58935552b385SBrandon 
58945552b385SBrandon   Level: intermediate
58955552b385SBrandon 
58965552b385SBrandon .seealso:
58975552b385SBrandon @*/
DMPlexGetGeomCntrlPntAndWeightData(DM dm,PetscHMapI * cpHashTable,PetscInt * cpCoordDataLength,PetscScalar ** cpCoordData,PetscInt * maxNumEquiv,Mat * cpEquiv,PetscHMapI * wHashTable,PetscInt * wDataLength,PetscScalar ** wData)5898ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomCntrlPntAndWeightData(DM dm, PetscHMapI *cpHashTable, PetscInt *cpCoordDataLength, PetscScalar **cpCoordData, PetscInt *maxNumEquiv, Mat *cpEquiv, PetscHMapI *wHashTable, PetscInt *wDataLength, PetscScalar **wData) PeNS
58995552b385SBrandon {
59005552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj, cpCoordDataLengthObj, wDataLengthObj, maxNumRelateObj;
59015552b385SBrandon   Vec            cntrlPtCoordsVec, cntrlPtWeightsVec;
59025552b385SBrandon   PetscInt      *cpCoordDataLengthPtr, *wDataLengthPtr, *maxNumEquivPtr;
59035552b385SBrandon   PetscHMapI     cpHashTableTemp, wHashTableTemp;
59045552b385SBrandon 
59055552b385SBrandon   PetscFunctionBeginHot;
59065552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
59075552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
59083a7d0413SPierre Jolivet   if (!modelObj) PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
59095552b385SBrandon 
5910ac530a7eSPierre Jolivet   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
59115552b385SBrandon 
59125552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
59135552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
59145552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
59155552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordDataLengthObj));
59165552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
59175552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
59185552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
5919bfe80ac4SPierre Jolivet   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Equivalency Matrix", (PetscObject *)cpEquiv));
59205552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject *)&maxNumRelateObj));
59215552b385SBrandon 
59225552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
59232a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(cpHashTableObj, &cpHashTableTemp));
59242a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(cpCoordDataLengthObj, &cpCoordDataLengthPtr));
59252a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(wHashTableObj, &wHashTableTemp));
59262a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(wDataLengthObj, &wDataLengthPtr));
59272a8381b2SBarry Smith   PetscCall(PetscContainerGetPointer(maxNumRelateObj, &maxNumEquivPtr));
59285552b385SBrandon 
59295552b385SBrandon   *cpCoordDataLength = *cpCoordDataLengthPtr;
59305552b385SBrandon   *wDataLength       = *wDataLengthPtr;
59315552b385SBrandon   *maxNumEquiv       = *maxNumEquivPtr;
59325552b385SBrandon   *cpHashTable       = cpHashTableTemp;
59335552b385SBrandon   *wHashTable        = wHashTableTemp;
59345552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, cpCoordData));
59355552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, wData));
59365552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
59375552b385SBrandon }
59385552b385SBrandon 
DMPlexRestoreGeomCntrlPntAndWeightData(DM dm,PetscHMapI * cpHashTable,PetscInt * cpCoordDataLength,PetscScalar ** cpCoordData,PetscInt * maxNumEquiv,Mat * cpEquiv,PetscHMapI * wHashTable,PetscInt * wDataLength,PetscScalar ** wData)59395552b385SBrandon PetscErrorCode DMPlexRestoreGeomCntrlPntAndWeightData(DM dm, PetscHMapI *cpHashTable, PetscInt *cpCoordDataLength, PetscScalar **cpCoordData, PetscInt *maxNumEquiv, Mat *cpEquiv, PetscHMapI *wHashTable, PetscInt *wDataLength, PetscScalar **wData)
59405552b385SBrandon {
59415552b385SBrandon   Vec cntrlPtCoordsVec, cntrlPtWeightsVec;
59425552b385SBrandon 
59435552b385SBrandon   PetscFunctionBeginHot;
59445552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
59455552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, cpCoordData));
59465552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
59475552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, wData));
59485552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
59495552b385SBrandon }
59505552b385SBrandon 
59515552b385SBrandon /*@C
59525552b385SBrandon   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 .
59535552b385SBrandon 
59545552b385SBrandon   Not collective
59555552b385SBrandon 
59565552b385SBrandon   Input Parameter:
59575552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
59585552b385SBrandon 
59595552b385SBrandon   Output Parameters:
59605552b385SBrandon + cpSurfGradHashTable - Hash Table Relating the Control Point ID to the the Row in the cpSurfGrad Matrix
59615552b385SBrandon . 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.
59625552b385SBrandon . cpArraySize         - The size of arrays gradSACP and gradVolCP and is equal to 3 * total number of Control Points in the Geometry
59635552b385SBrandon . 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.
5964bfe80ac4SPierre 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.
59655552b385SBrandon . wArraySize          - The size of arrayws gradSAW and gradVolW and is equal to the total number of Control Points in the Geometry.
59665552b385SBrandon . gradSAW             - Array containing the Surface Area Gradient with respect to Control Point Weight. Data is arranged by Control Point ID.
59675552b385SBrandon - gradVolW            - Array containing the Volume Gradient with respect to Control Point Weight. Data is arranged by Control Point ID.
59685552b385SBrandon 
59695552b385SBrandon   Notes:
59705552b385SBrandon   Must Call DMPLexGeomDataAndGrads() before calling this function.
59715552b385SBrandon 
59725552b385SBrandon   gradVolCP and gradVolW are only available when DMPlexGeomDataAndGrads() is called with fullGeomGrad = PETSC_TRUE.
59735552b385SBrandon 
59745552b385SBrandon   Level: intermediate
59755552b385SBrandon 
59765552b385SBrandon .seealso: DMPlexGeomDataAndGrads
59775552b385SBrandon @*/
DMPlexGetGeomGradData(DM dm,PetscHMapI * cpSurfGradHashTable,Mat * cpSurfGrad,PetscInt * cpArraySize,PetscScalar ** gradSACP,PetscScalar ** gradVolCP,PetscInt * wArraySize,PetscScalar ** gradSAW,PetscScalar ** gradVolW)59785552b385SBrandon PetscErrorCode DMPlexGetGeomGradData(DM dm, PetscHMapI *cpSurfGradHashTable, Mat *cpSurfGrad, PetscInt *cpArraySize, PetscScalar **gradSACP, PetscScalar **gradVolCP, PetscInt *wArraySize, PetscScalar **gradSAW, PetscScalar **gradVolW)
59795552b385SBrandon {
59805552b385SBrandon   PetscContainer modelObj, cpSurfGradHashTableObj, cpArraySizeObj, wArraySizeObj;
59815552b385SBrandon   Vec            gradSACPVec, gradVolCPVec, gradSAWVec, gradVolWVec;
59825552b385SBrandon   PetscInt      *cpArraySizePtr, *wArraySizePtr;
59835552b385SBrandon   PetscHMapI     cpSurfGradHashTableTemp;
59845552b385SBrandon 
59855552b385SBrandon   PetscFunctionBeginHot;
59865552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
59875552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
59883a7d0413SPierre Jolivet   if (!modelObj) PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
59895552b385SBrandon 
5990ac530a7eSPierre Jolivet   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
59915552b385SBrandon 
59925552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
59935552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject *)&cpSurfGradHashTableObj));
59945552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Matrix", (PetscObject *)cpSurfGrad));
59955552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpArraySizeObj));
59965552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject *)&gradSACPVec));
59975552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Control Point Gradient", (PetscObject *)&gradVolCPVec));
59985552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wArraySizeObj));
59995552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject *)&gradSAWVec));
60005552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Weights Gradient", (PetscObject *)&gradVolWVec));
60015552b385SBrandon 
60025552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
60035552b385SBrandon   if (cpSurfGradHashTableObj) {
60042a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cpSurfGradHashTableObj, &cpSurfGradHashTableTemp));
60055552b385SBrandon     *cpSurfGradHashTable = cpSurfGradHashTableTemp;
60065552b385SBrandon   }
60075552b385SBrandon 
60085552b385SBrandon   if (cpArraySizeObj) {
60092a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cpArraySizeObj, &cpArraySizePtr));
60105552b385SBrandon     *cpArraySize = *cpArraySizePtr;
60115552b385SBrandon   }
60125552b385SBrandon 
60135552b385SBrandon   if (gradSACPVec) PetscCall(VecGetArrayWrite(gradSACPVec, gradSACP));
60145552b385SBrandon   if (gradVolCPVec) PetscCall(VecGetArrayWrite(gradVolCPVec, gradVolCP));
60155552b385SBrandon   if (gradSAWVec) PetscCall(VecGetArrayWrite(gradSAWVec, gradSAW));
60165552b385SBrandon   if (gradVolWVec) PetscCall(VecGetArrayWrite(gradVolWVec, gradVolW));
60175552b385SBrandon 
60185552b385SBrandon   if (wArraySizeObj) {
60192a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(wArraySizeObj, &wArraySizePtr));
60205552b385SBrandon     *wArraySize = *wArraySizePtr;
60215552b385SBrandon   }
60225552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
60235552b385SBrandon }
60245552b385SBrandon 
DMPlexRestoreGeomGradData(DM dm,PetscHMapI * cpSurfGradHashTable,Mat * cpSurfGrad,PetscInt * cpArraySize,PetscScalar ** gradSACP,PetscScalar ** gradVolCP,PetscInt * wArraySize,PetscScalar ** gradSAW,PetscScalar ** gradVolW)60255552b385SBrandon PetscErrorCode DMPlexRestoreGeomGradData(DM dm, PetscHMapI *cpSurfGradHashTable, Mat *cpSurfGrad, PetscInt *cpArraySize, PetscScalar **gradSACP, PetscScalar **gradVolCP, PetscInt *wArraySize, PetscScalar **gradSAW, PetscScalar **gradVolW)
60265552b385SBrandon {
60275552b385SBrandon   Vec gradSACPVec, gradVolCPVec, gradSAWVec, gradVolWVec;
60287bee2925SMatthew Knepley 
60297bee2925SMatthew Knepley   PetscFunctionBegin;
60305552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject *)&gradSACPVec));
60315552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Control Point Gradient", (PetscObject *)&gradVolCPVec));
60325552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject *)&gradSAWVec));
60335552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Weights Gradient", (PetscObject *)&gradVolWVec));
60345552b385SBrandon 
60355552b385SBrandon   if (gradSACPVec) PetscCall(VecRestoreArrayWrite(gradSACPVec, gradSACP));
60365552b385SBrandon   if (gradVolCPVec) PetscCall(VecRestoreArrayWrite(gradVolCPVec, gradVolCP));
60375552b385SBrandon   if (gradSAWVec) PetscCall(VecRestoreArrayWrite(gradSAWVec, gradSAW));
60385552b385SBrandon   if (gradVolWVec) PetscCall(VecRestoreArrayWrite(gradVolWVec, gradVolW));
60393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60407bee2925SMatthew Knepley }
60415552b385SBrandon 
60425552b385SBrandon /*@C
60435552b385SBrandon   DMPlexGetGeomCntrlPntMaps - Gets arrays which maps Control Point IDs to their associated Geometry FACE, EDGE, and VERTEX.
60445552b385SBrandon 
60455552b385SBrandon   Not collective
60465552b385SBrandon 
60475552b385SBrandon   Input Parameter:
60485552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
60495552b385SBrandon 
60505552b385SBrandon   Output Parameters:
60515552b385SBrandon + numCntrlPnts            - Number of Control Points defining the Geometry attached to the DMPlex
60525552b385SBrandon . cntrlPntFaceMap         - Array containing the FACE ID for the Control Point. Array index corresponds to Control Point ID.
60535552b385SBrandon . cntrlPntWeightFaceMap   - Array containing the FACE ID for the Control Point Weight. Array index corresponds to Control Point ID.
60545552b385SBrandon . cntrlPntEdgeMap         - Array containing the EDGE ID for the Control Point. Array index corresponds to Control Point ID.
60555552b385SBrandon . cntrlPntWeightEdgeMap   - Array containing the EDGE ID for the Control Point Weight. Array index corresponds to Control Point ID.
60565552b385SBrandon . cntrlPntVertexMap       - Array containing the VERTEX ID for the Control Point. Array index corresponds to Control Point ID.
60575552b385SBrandon - cntrlPntWeightVertexMap - Array containing the VERTEX ID for the Control Point Weight. Array index corresponds to Control Point ID.
60585552b385SBrandon 
60595552b385SBrandon   Note:
60605552b385SBrandon   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.
60615552b385SBrandon 
60625552b385SBrandon   Level: intermediate
60635552b385SBrandon 
60645552b385SBrandon .seealso: DMPlexGeomDataAndGrads
60655552b385SBrandon @*/
DMPlexGetGeomCntrlPntMaps(DM dm,PetscInt * numCntrlPnts,PetscInt ** cntrlPntFaceMap,PetscInt ** cntrlPntWeightFaceMap,PetscInt ** cntrlPntEdgeMap,PetscInt ** cntrlPntWeightEdgeMap,PetscInt ** cntrlPntVertexMap,PetscInt ** cntrlPntWeightVertexMap)60665552b385SBrandon PetscErrorCode DMPlexGetGeomCntrlPntMaps(DM dm, PetscInt *numCntrlPnts, PetscInt **cntrlPntFaceMap, PetscInt **cntrlPntWeightFaceMap, PetscInt **cntrlPntEdgeMap, PetscInt **cntrlPntWeightEdgeMap, PetscInt **cntrlPntVertexMap, PetscInt **cntrlPntWeightVertexMap)
60675552b385SBrandon {
60685552b385SBrandon   PetscFunctionBeginHot;
60695552b385SBrandon   #ifdef PETSC_HAVE_EGADS
60705552b385SBrandon   PetscContainer modelObj, numCntrlPntsObj, cntrlPntFaceMapObj, cntrlPntWeightFaceMapObj, cntrlPntEdgeMapObj, cntrlPntWeightEdgeMapObj, cntrlPntVertexMapObj, cntrlPntWeightVertexMapObj;
60715552b385SBrandon   PetscInt      *numCntrlPntsPtr, *cntrlPntFaceMapPtr, *cntrlPntWeightFaceMapPtr, *cntrlPntEdgeMapPtr, *cntrlPntWeightEdgeMapPtr, *cntrlPntVertexMapPtr, *cntrlPntWeightVertexMapPtr;
60725552b385SBrandon 
60735552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
60745552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
60753a7d0413SPierre Jolivet   if (!modelObj) PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
60765552b385SBrandon 
6077ac530a7eSPierre Jolivet   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
60785552b385SBrandon 
60795552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
60805552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&numCntrlPntsObj));
60815552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Face Map", (PetscObject *)&cntrlPntFaceMapObj));
60825552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject *)&cntrlPntWeightFaceMapObj));
60835552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Edge Map", (PetscObject *)&cntrlPntEdgeMapObj));
60845552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject *)&cntrlPntWeightEdgeMapObj));
60855552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Vertex Map", (PetscObject *)&cntrlPntVertexMapObj));
60865552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject *)&cntrlPntWeightVertexMapObj));
60875552b385SBrandon 
60885552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
60895552b385SBrandon   if (numCntrlPntsObj) {
60902a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(numCntrlPntsObj, &numCntrlPntsPtr));
60915552b385SBrandon     *numCntrlPnts = *numCntrlPntsPtr;
60925552b385SBrandon   }
60935552b385SBrandon 
60945552b385SBrandon   if (cntrlPntFaceMapObj) {
60952a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cntrlPntFaceMapObj, &cntrlPntFaceMapPtr));
60965552b385SBrandon     *cntrlPntFaceMap = cntrlPntFaceMapPtr;
60975552b385SBrandon   }
60985552b385SBrandon 
60995552b385SBrandon   if (cntrlPntWeightFaceMapObj) {
61002a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cntrlPntWeightFaceMapObj, &cntrlPntWeightFaceMapPtr));
61015552b385SBrandon     *cntrlPntWeightFaceMap = cntrlPntWeightFaceMapPtr;
61025552b385SBrandon   }
61035552b385SBrandon 
61045552b385SBrandon   if (cntrlPntEdgeMapObj) {
61052a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cntrlPntEdgeMapObj, &cntrlPntEdgeMapPtr));
61065552b385SBrandon     *cntrlPntEdgeMap = cntrlPntEdgeMapPtr;
61075552b385SBrandon   }
61085552b385SBrandon 
61095552b385SBrandon   if (cntrlPntWeightEdgeMapObj) {
61102a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cntrlPntWeightEdgeMapObj, &cntrlPntWeightEdgeMapPtr));
61115552b385SBrandon     *cntrlPntWeightEdgeMap = cntrlPntWeightEdgeMapPtr;
61125552b385SBrandon   }
61135552b385SBrandon 
61145552b385SBrandon   if (cntrlPntVertexMapObj) {
61152a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cntrlPntVertexMapObj, &cntrlPntVertexMapPtr));
61165552b385SBrandon     *cntrlPntVertexMap = cntrlPntVertexMapPtr;
61175552b385SBrandon   }
61185552b385SBrandon 
61195552b385SBrandon   if (cntrlPntWeightVertexMapObj) {
61202a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(cntrlPntWeightVertexMapObj, &cntrlPntWeightVertexMapPtr));
61215552b385SBrandon     *cntrlPntWeightVertexMap = cntrlPntWeightVertexMapPtr;
61225552b385SBrandon   }
61235552b385SBrandon 
61245552b385SBrandon   #endif
61255552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
61265552b385SBrandon }
61275552b385SBrandon 
61285552b385SBrandon #endif
6129