xref: /petsc/src/dm/impls/plex/plexegads.c (revision 5552b385b77b214b234683fbe1b434751e6350f0)
1*5552b385SBrandon #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
19*5552b385SBrandon   #include <petscdmplexegads.h>
20c1cad2e7SMatthew G. Knepley 
21*5552b385SBrandon PETSC_INTERN PetscErrorCode DMSnapToGeomModel_EGADS_Internal(DM, PetscInt, ego, PetscInt, PetscInt, PetscInt, const PetscScalar[], PetscScalar[], PetscBool);
22*5552b385SBrandon PETSC_INTERN PetscErrorCode DMPlex_Geom_EDGE_XYZtoUV_Internal(const PetscScalar[], ego, const PetscScalar[], const PetscInt, const PetscInt, PetscScalar[], PetscBool);
23*5552b385SBrandon PETSC_INTERN PetscErrorCode DMPlex_Geom_FACE_XYZtoUV_Internal(const PetscScalar[], ego, const PetscScalar[], const PetscInt, const PetscInt, PetscScalar[], PetscBool);
24*5552b385SBrandon 
25*5552b385SBrandon PetscErrorCode DMPlex_EGADS_GeomDecode_Internal(const PetscInt geomClass, const PetscInt geomType, char **retClass, char **retType)
26d71ae5a4SJacob Faibussowitsch {
27*5552b385SBrandon   PetscFunctionBeginHot;
28*5552b385SBrandon   /* EGADS Object Type */
29*5552b385SBrandon   if (geomClass == CONTXT) { *retClass = (char *)"CONTEXT"; }
30*5552b385SBrandon   if (geomClass == TRANSFORM) { *retClass = (char *)"TRANSFORM"; }
31*5552b385SBrandon   if (geomClass == TESSELLATION) { *retClass = (char *)"TESSELLATION"; }
32*5552b385SBrandon   if (geomClass == NIL) { *retClass = (char *)"NIL"; }
33*5552b385SBrandon   if (geomClass == EMPTY) { *retClass = (char *)"EMPTY"; }
34*5552b385SBrandon   if (geomClass == REFERENCE) { *retClass = (char *)"REFERENCE"; }
35*5552b385SBrandon   if (geomClass == PCURVE) { *retClass = (char *)"PCURVE"; }
36*5552b385SBrandon   if (geomClass == CURVE) { *retClass = (char *)"CURVE"; }
37*5552b385SBrandon   if (geomClass == SURFACE) { *retClass = (char *)"SURFACE"; }
38*5552b385SBrandon   if (geomClass == NODE) { *retClass = (char *)"NODE"; }
39*5552b385SBrandon   if (geomClass == EDGE) { *retClass = (char *)"EDGE"; }
40*5552b385SBrandon   if (geomClass == LOOP) { *retClass = (char *)"LOOP"; }
41*5552b385SBrandon   if (geomClass == FACE) { *retClass = (char *)"FACE"; }
42*5552b385SBrandon   if (geomClass == SHELL) { *retClass = (char *)"SHELL"; }
43*5552b385SBrandon   if (geomClass == BODY) { *retClass = (char *)"BODY"; }
44*5552b385SBrandon   if (geomClass == MODEL) { *retClass = (char *)"MODEL"; }
45*5552b385SBrandon 
46*5552b385SBrandon   /* PCURVES & CURVES */
47*5552b385SBrandon   if (geomClass == PCURVE || geomClass == CURVE) {
48*5552b385SBrandon     if (geomType == LINE) { *retType = (char *)"LINE"; }
49*5552b385SBrandon     if (geomType == CIRCLE) { *retType = (char *)"CIRCLE"; }
50*5552b385SBrandon     if (geomType == ELLIPSE) { *retType = (char *)"ELLIPSE"; }
51*5552b385SBrandon     if (geomType == PARABOLA) { *retType = (char *)"PARABOLA"; }
52*5552b385SBrandon     if (geomType == HYPERBOLA) { *retType = (char *)"HYPERBOLA"; }
53*5552b385SBrandon     if (geomType == TRIMMED) { *retType = (char *)"TRIMMED"; }
54*5552b385SBrandon     if (geomType == BEZIER) { *retType = (char *)"BEZIER"; }
55*5552b385SBrandon     if (geomType == BSPLINE) { *retType = (char *)"BSPLINE"; }
56*5552b385SBrandon     if (geomType == OFFSET) { *retType = (char *)"OFFSET"; }
57*5552b385SBrandon   }
58*5552b385SBrandon 
59*5552b385SBrandon   /* SURFACE */
60*5552b385SBrandon   if (geomClass == SURFACE) {
61*5552b385SBrandon     if (geomType == PLANE) { *retType = (char *)"PLANE"; }
62*5552b385SBrandon     if (geomType == SPHERICAL) { *retType = (char *)"SPHERICAL"; }
63*5552b385SBrandon     if (geomType == CYLINDRICAL) { *retType = (char *)"CYLINDRICAL"; }
64*5552b385SBrandon     if (geomType == REVOLUTION) { *retType = (char *)"REVOLUTION"; }
65*5552b385SBrandon     if (geomType == TOROIDAL) { *retType = (char *)"TOROIDAL"; }
66*5552b385SBrandon     if (geomType == CONICAL) { *retType = (char *)"CONICAL"; }
67*5552b385SBrandon     if (geomType == EXTRUSION) { *retType = (char *)"EXTRUSION"; }
68*5552b385SBrandon     if (geomType == BEZIER) { *retType = (char *)"BEZIER"; }
69*5552b385SBrandon     if (geomType == BSPLINE) { *retType = (char *)"BSPLINE"; }
70*5552b385SBrandon   }
71*5552b385SBrandon 
72*5552b385SBrandon   /* TOPOLOGY */
73*5552b385SBrandon   if (geomClass == NODE || geomClass == EDGE || geomClass == LOOP || geomClass == FACE || geomClass == SHELL || geomClass == BODY || geomClass == MODEL) {
74*5552b385SBrandon     if (geomType == SREVERSE) { *retType = (char *)"SREVERSE"; }
75*5552b385SBrandon     if (geomType == NOMTYPE) { *retType = (char *)"NOMTYPE"; }
76*5552b385SBrandon     if (geomType == SFORWARD && geomClass == FACE) { *retType = (char *)"SFORWARD"; }
77*5552b385SBrandon     if (geomType == ONENODE && geomClass == EDGE) { *retType = (char *)"ONENODE"; }
78*5552b385SBrandon     if (geomType == TWONODE) { *retType = (char *)"TWONODE"; }
79*5552b385SBrandon     if (geomType == OPEN) { *retType = (char *)"OPEN"; }
80*5552b385SBrandon     if (geomType == CLOSED) { *retType = (char *)"CLOSED"; }
81*5552b385SBrandon     if (geomType == DEGENERATE) { *retType = (char *)"DEGENERATE"; }
82*5552b385SBrandon     if (geomType == WIREBODY) { *retType = (char *)"WIREBODY"; }
83*5552b385SBrandon     if (geomType == FACEBODY) { *retType = (char *)"FACEBODY"; }
84*5552b385SBrandon     if (geomType == SHEETBODY) { *retType = (char *)"SHEETBODY"; }
85*5552b385SBrandon     if (geomType == SOLIDBODY) { *retType = (char *)"SOLIDBODY"; }
86*5552b385SBrandon   }
87*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
88*5552b385SBrandon }
89*5552b385SBrandon 
90*5552b385SBrandon PetscErrorCode DMPlex_EGADS_EDGE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[])
91*5552b385SBrandon {
92*5552b385SBrandon   //
93*5552b385SBrandon   //
94*5552b385SBrandon   // Depreciated. Changed all references to DMPlex_Geom_FACE_XYZtoUV_Internal()
95*5552b385SBrandon   //
96*5552b385SBrandon   //
97*5552b385SBrandon 
98*5552b385SBrandon   PetscInt    loopCntr = 0;
99*5552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, obj_old, obj_tmp, target;
100*5552b385SBrandon   PetscScalar delta, A, b;
101*5552b385SBrandon   PetscScalar ts[2], tt[2], eval[18], data[18];
102*5552b385SBrandon 
103*5552b385SBrandon   PetscFunctionBeginHot;
104*5552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
105*5552b385SBrandon   lambda = 1.0;
106*5552b385SBrandon   tolr   = 1.0;
107*5552b385SBrandon   target = 1.0E-20;
108*5552b385SBrandon   ts[0]  = (range[0] + range[1]) / 2.;
109*5552b385SBrandon 
110*5552b385SBrandon   while (tolr >= target) {
111*5552b385SBrandon     PetscCall(EG_evaluate(obj, ts, eval));
112*5552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
113*5552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
114*5552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
115*5552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
116*5552b385SBrandon 
117*5552b385SBrandon     if (obj_old < target) {
118*5552b385SBrandon       tolr = obj_old;
119*5552b385SBrandon       break;
120*5552b385SBrandon     }
121*5552b385SBrandon 
122*5552b385SBrandon     A = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
123*5552b385SBrandon     if (A == 0.0) {
124*5552b385SBrandon       PetscCall(PetscPrintf(PETSC_COMM_SELF, "A = 0.0 \n"));
125*5552b385SBrandon       break;
126*5552b385SBrandon     }
127*5552b385SBrandon     b = eval[3] * dx + eval[4] * dy + eval[5] * dz;
128*5552b385SBrandon 
129*5552b385SBrandon     /* Solve A*delta = b */
130*5552b385SBrandon     delta = b / A;
131*5552b385SBrandon 
132*5552b385SBrandon     /* Find a temp (u,v) and associated objective function */
133*5552b385SBrandon     tt[0] = ts[0] + delta;
134*5552b385SBrandon     if (tt[0] < range[0]) {
135*5552b385SBrandon       tt[0] = range[0];
136*5552b385SBrandon       delta = tt[0] - ts[0];
137*5552b385SBrandon     }
138*5552b385SBrandon     if (tt[0] > range[1]) {
139*5552b385SBrandon       tt[0] = range[1];
140*5552b385SBrandon       delta = tt[0] - ts[0];
141*5552b385SBrandon     }
142*5552b385SBrandon 
143*5552b385SBrandon     PetscCall(EG_evaluate(obj, tt, data));
144*5552b385SBrandon 
145*5552b385SBrandon     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]);
146*5552b385SBrandon 
147*5552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
148*5552b385SBrandon     if (obj_tmp < obj_old) {
149*5552b385SBrandon       obj_old = obj_tmp;
150*5552b385SBrandon       ts[0]   = tt[0];
151*5552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
152*5552b385SBrandon       lambda /= 2.0;
153*5552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
154*5552b385SBrandon       if (obj_old < target) {
155*5552b385SBrandon         tolr = obj_old;
156*5552b385SBrandon         break;
157*5552b385SBrandon       }
158*5552b385SBrandon     } else {
159*5552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
160*5552b385SBrandon       lambda *= 2.0;
161*5552b385SBrandon     }
162*5552b385SBrandon 
163*5552b385SBrandon     if ((tt[0] == range[0]) || (tt[0] == range[1])) break;
164*5552b385SBrandon     if (fabs(delta) < target) {
165*5552b385SBrandon       tolr = obj_old;
166*5552b385SBrandon       break;
167*5552b385SBrandon     }
168*5552b385SBrandon 
169*5552b385SBrandon     tolr = obj_old;
170*5552b385SBrandon 
171*5552b385SBrandon     loopCntr += 1;
172*5552b385SBrandon     if (loopCntr > 100) break;
173*5552b385SBrandon   }
174*5552b385SBrandon   paramsV[v * 3 + 0] = ts[0];
175*5552b385SBrandon   paramsV[v * 3 + 1] = 0.;
176*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
177*5552b385SBrandon }
178*5552b385SBrandon 
179*5552b385SBrandon PetscErrorCode DMPlex_Geom_EDGE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[], PetscBool islite)
180*5552b385SBrandon {
181*5552b385SBrandon   PetscInt    loopCntr = 0;
182*5552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, obj_old, obj_tmp, target;
183*5552b385SBrandon   PetscScalar delta, A, b;
184*5552b385SBrandon   PetscScalar ts[2], tt[2], eval[18], data[18];
185*5552b385SBrandon 
186*5552b385SBrandon   PetscFunctionBeginHot;
187*5552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
188*5552b385SBrandon   lambda = 1.0;
189*5552b385SBrandon   tolr   = 1.0;
190*5552b385SBrandon   target = 1.0E-20;
191*5552b385SBrandon   ts[0]  = (range[0] + range[1]) / 2.;
192*5552b385SBrandon 
193*5552b385SBrandon   while (tolr >= target) {
194*5552b385SBrandon     if (islite) {
195*5552b385SBrandon       PetscCall(EGlite_evaluate(obj, ts, eval));
196*5552b385SBrandon     } else {
197*5552b385SBrandon       PetscCall(EG_evaluate(obj, ts, eval));
198*5552b385SBrandon     }
199*5552b385SBrandon 
200*5552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
201*5552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
202*5552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
203*5552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
204*5552b385SBrandon 
205*5552b385SBrandon     if (obj_old < target) {
206*5552b385SBrandon       tolr = obj_old;
207*5552b385SBrandon       break;
208*5552b385SBrandon     }
209*5552b385SBrandon 
210*5552b385SBrandon     A = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
211*5552b385SBrandon     if (A == 0.0) {
212*5552b385SBrandon       PetscCall(PetscPrintf(PETSC_COMM_SELF, "A = 0.0 \n"));
213*5552b385SBrandon       break;
214*5552b385SBrandon     }
215*5552b385SBrandon     b = eval[3] * dx + eval[4] * dy + eval[5] * dz;
216*5552b385SBrandon 
217*5552b385SBrandon     /* Solve A*delta = b */
218*5552b385SBrandon     delta = b / A;
219*5552b385SBrandon 
220*5552b385SBrandon     /* Find a temp (u,v) and associated objective function */
221*5552b385SBrandon     tt[0] = ts[0] + delta;
222*5552b385SBrandon     if (tt[0] < range[0]) {
223*5552b385SBrandon       tt[0] = range[0];
224*5552b385SBrandon       delta = tt[0] - ts[0];
225*5552b385SBrandon     }
226*5552b385SBrandon     if (tt[0] > range[1]) {
227*5552b385SBrandon       tt[0] = range[1];
228*5552b385SBrandon       delta = tt[0] - ts[0];
229*5552b385SBrandon     }
230*5552b385SBrandon 
231*5552b385SBrandon     if (islite) {
232*5552b385SBrandon       PetscCall(EGlite_evaluate(obj, tt, data));
233*5552b385SBrandon     } else {
234*5552b385SBrandon       PetscCall(EG_evaluate(obj, tt, data));
235*5552b385SBrandon     }
236*5552b385SBrandon 
237*5552b385SBrandon     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]);
238*5552b385SBrandon 
239*5552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
240*5552b385SBrandon     if (obj_tmp < obj_old) {
241*5552b385SBrandon       obj_old = obj_tmp;
242*5552b385SBrandon       ts[0]   = tt[0];
243*5552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
244*5552b385SBrandon       lambda /= 2.0;
245*5552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
246*5552b385SBrandon       if (obj_old < target) {
247*5552b385SBrandon         tolr = obj_old;
248*5552b385SBrandon         break;
249*5552b385SBrandon       }
250*5552b385SBrandon     } else {
251*5552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
252*5552b385SBrandon       lambda *= 2.0;
253*5552b385SBrandon     }
254*5552b385SBrandon 
255*5552b385SBrandon     if ((tt[0] == range[0]) || (tt[0] == range[1])) break;
256*5552b385SBrandon     if (fabs(delta) < target) {
257*5552b385SBrandon       tolr = obj_old;
258*5552b385SBrandon       break;
259*5552b385SBrandon     }
260*5552b385SBrandon 
261*5552b385SBrandon     tolr = obj_old;
262*5552b385SBrandon 
263*5552b385SBrandon     loopCntr += 1;
264*5552b385SBrandon     if (loopCntr > 100) break;
265*5552b385SBrandon   }
266*5552b385SBrandon   paramsV[v * 3 + 0] = ts[0];
267*5552b385SBrandon   paramsV[v * 3 + 1] = 0.;
268*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
269*5552b385SBrandon }
270*5552b385SBrandon 
271*5552b385SBrandon PetscErrorCode DMPlex_EGADS_FACE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[])
272*5552b385SBrandon {
273*5552b385SBrandon   //
274*5552b385SBrandon   //
275*5552b385SBrandon   // Depreciated. Changed all references to DMPlex_Geom_FACE_XYZtoUV_Internal()
276*5552b385SBrandon   //
277*5552b385SBrandon   //
278*5552b385SBrandon 
279*5552b385SBrandon   PetscInt    loopCntr = 0;
280*5552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, denom, obj_old, obj_tmp, target;
281*5552b385SBrandon   PetscScalar uvs[2], uvt[2], delta[2], A[4], b[2], eval[18], data[18];
282*5552b385SBrandon 
283*5552b385SBrandon   PetscFunctionBeginHot;
284*5552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
285*5552b385SBrandon   lambda = 1.0;
286*5552b385SBrandon   tolr   = 1.0;
287*5552b385SBrandon   target = 1.0E-20;
288*5552b385SBrandon   uvs[0] = (range[0] + range[1]) / 2.;
289*5552b385SBrandon   uvs[1] = (range[2] + range[3]) / 2.;
290*5552b385SBrandon 
291*5552b385SBrandon   while (tolr >= target) {
292*5552b385SBrandon     PetscCall(EG_evaluate(obj, uvs, eval));
293*5552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
294*5552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
295*5552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
296*5552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
297*5552b385SBrandon 
298*5552b385SBrandon     if (obj_old < target) {
299*5552b385SBrandon       tolr = obj_old;
300*5552b385SBrandon       break;
301*5552b385SBrandon     }
302*5552b385SBrandon 
303*5552b385SBrandon     A[0] = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
304*5552b385SBrandon     A[1] = eval[3] * eval[6] + eval[4] * eval[7] + eval[5] * eval[8];
305*5552b385SBrandon     A[2] = A[1];
306*5552b385SBrandon     A[3] = (eval[6] * eval[6] + eval[7] * eval[7] + eval[8] * eval[8]) * (1.0 + lambda);
307*5552b385SBrandon 
308*5552b385SBrandon     b[0] = eval[3] * dx + eval[4] * dy + eval[5] * dz;
309*5552b385SBrandon     b[1] = eval[6] * dx + eval[7] * dy + eval[8] * dz;
310*5552b385SBrandon 
311*5552b385SBrandon     /* Solve A*delta = b using Cramer's Rule */
312*5552b385SBrandon     denom = A[0] * A[3] - A[2] * A[1];
313*5552b385SBrandon     if (denom == 0.0) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "denom = 0.0 \n")); }
314*5552b385SBrandon     delta[0] = (b[0] * A[3] - b[1] * A[1]) / denom;
315*5552b385SBrandon     delta[1] = (A[0] * b[1] - A[2] * b[0]) / denom;
316*5552b385SBrandon 
317*5552b385SBrandon     /* Find a temp (u,v) and associated objective function */
318*5552b385SBrandon     uvt[0] = uvs[0] + delta[0];
319*5552b385SBrandon     uvt[1] = uvs[1] + delta[1];
320*5552b385SBrandon 
321*5552b385SBrandon     if (uvt[0] < range[0]) {
322*5552b385SBrandon       uvt[0]   = range[0];
323*5552b385SBrandon       delta[0] = uvt[0] - uvs[0];
324*5552b385SBrandon     }
325*5552b385SBrandon     if (uvt[0] > range[1]) {
326*5552b385SBrandon       uvt[0]   = range[1];
327*5552b385SBrandon       delta[0] = uvt[0] - uvs[0];
328*5552b385SBrandon     }
329*5552b385SBrandon     if (uvt[1] < range[2]) {
330*5552b385SBrandon       uvt[1]   = range[2];
331*5552b385SBrandon       delta[1] = uvt[1] - uvs[1];
332*5552b385SBrandon     }
333*5552b385SBrandon     if (uvt[1] > range[3]) {
334*5552b385SBrandon       uvt[1]   = range[3];
335*5552b385SBrandon       delta[1] = uvt[1] - uvs[1];
336*5552b385SBrandon     }
337*5552b385SBrandon 
338*5552b385SBrandon     PetscCall(EG_evaluate(obj, uvt, data));
339*5552b385SBrandon 
340*5552b385SBrandon     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]);
341*5552b385SBrandon 
342*5552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
343*5552b385SBrandon     if (obj_tmp < obj_old) {
344*5552b385SBrandon       obj_old = obj_tmp;
345*5552b385SBrandon       uvs[0]  = uvt[0];
346*5552b385SBrandon       uvs[1]  = uvt[1];
347*5552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
348*5552b385SBrandon       lambda /= 2.0;
349*5552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
350*5552b385SBrandon       if (obj_old < target) {
351*5552b385SBrandon         tolr = obj_old;
352*5552b385SBrandon         break;
353*5552b385SBrandon       }
354*5552b385SBrandon     } else {
355*5552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
356*5552b385SBrandon       lambda *= 2.0;
357*5552b385SBrandon     }
358*5552b385SBrandon 
359*5552b385SBrandon     if (sqrt(delta[0] * delta[0] + delta[1] * delta[1]) < target) {
360*5552b385SBrandon       tolr = obj_old;
361*5552b385SBrandon       break;
362*5552b385SBrandon     }
363*5552b385SBrandon 
364*5552b385SBrandon     tolr = obj_old;
365*5552b385SBrandon 
366*5552b385SBrandon     loopCntr += 1;
367*5552b385SBrandon     if (loopCntr > 100) break;
368*5552b385SBrandon   }
369*5552b385SBrandon   paramsV[v * 3 + 0] = uvs[0];
370*5552b385SBrandon   paramsV[v * 3 + 1] = uvs[1];
371*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
372*5552b385SBrandon }
373*5552b385SBrandon 
374*5552b385SBrandon PetscErrorCode DMPlex_Geom_FACE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[], PetscBool islite)
375*5552b385SBrandon {
376*5552b385SBrandon   PetscInt    loopCntr = 0;
377*5552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, denom, obj_old, obj_tmp, target;
378*5552b385SBrandon   PetscScalar uvs[2], uvt[2], delta[2], A[4], b[2], eval[18], data[18];
379*5552b385SBrandon 
380*5552b385SBrandon   PetscFunctionBeginHot;
381*5552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
382*5552b385SBrandon   lambda = 1.0;
383*5552b385SBrandon   tolr   = 1.0;
384*5552b385SBrandon   target = 1.0E-20;
385*5552b385SBrandon   uvs[0] = (range[0] + range[1]) / 2.;
386*5552b385SBrandon   uvs[1] = (range[2] + range[3]) / 2.;
387*5552b385SBrandon 
388*5552b385SBrandon   while (tolr >= target) {
389*5552b385SBrandon     if (islite) {
390*5552b385SBrandon       PetscCallEGADS(EGlite_evaluate, (obj, uvs, eval));
391*5552b385SBrandon     } else {
392*5552b385SBrandon       PetscCallEGADS(EG_evaluate, (obj, uvs, eval));
393*5552b385SBrandon     }
394*5552b385SBrandon 
395*5552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
396*5552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
397*5552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
398*5552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
399*5552b385SBrandon 
400*5552b385SBrandon     if (obj_old < target) {
401*5552b385SBrandon       tolr = obj_old;
402*5552b385SBrandon       break;
403*5552b385SBrandon     }
404*5552b385SBrandon 
405*5552b385SBrandon     A[0] = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
406*5552b385SBrandon     A[1] = eval[3] * eval[6] + eval[4] * eval[7] + eval[5] * eval[8];
407*5552b385SBrandon     A[2] = A[1];
408*5552b385SBrandon     A[3] = (eval[6] * eval[6] + eval[7] * eval[7] + eval[8] * eval[8]) * (1.0 + lambda);
409*5552b385SBrandon 
410*5552b385SBrandon     b[0] = eval[3] * dx + eval[4] * dy + eval[5] * dz;
411*5552b385SBrandon     b[1] = eval[6] * dx + eval[7] * dy + eval[8] * dz;
412*5552b385SBrandon 
413*5552b385SBrandon     /* Solve A*delta = b using Cramer's Rule */
414*5552b385SBrandon     denom = A[0] * A[3] - A[2] * A[1];
415*5552b385SBrandon     if (denom == 0.0) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "denom = 0.0 \n")); }
416*5552b385SBrandon     delta[0] = (b[0] * A[3] - b[1] * A[1]) / denom;
417*5552b385SBrandon     delta[1] = (A[0] * b[1] - A[2] * b[0]) / denom;
418*5552b385SBrandon 
419*5552b385SBrandon     /* Find a temp (u,v) and associated objective function */
420*5552b385SBrandon     uvt[0] = uvs[0] + delta[0];
421*5552b385SBrandon     uvt[1] = uvs[1] + delta[1];
422*5552b385SBrandon 
423*5552b385SBrandon     if (uvt[0] < range[0]) {
424*5552b385SBrandon       uvt[0]   = range[0];
425*5552b385SBrandon       delta[0] = uvt[0] - uvs[0];
426*5552b385SBrandon     }
427*5552b385SBrandon     if (uvt[0] > range[1]) {
428*5552b385SBrandon       uvt[0]   = range[1];
429*5552b385SBrandon       delta[0] = uvt[0] - uvs[0];
430*5552b385SBrandon     }
431*5552b385SBrandon     if (uvt[1] < range[2]) {
432*5552b385SBrandon       uvt[1]   = range[2];
433*5552b385SBrandon       delta[1] = uvt[1] - uvs[1];
434*5552b385SBrandon     }
435*5552b385SBrandon     if (uvt[1] > range[3]) {
436*5552b385SBrandon       uvt[1]   = range[3];
437*5552b385SBrandon       delta[1] = uvt[1] - uvs[1];
438*5552b385SBrandon     }
439*5552b385SBrandon 
440*5552b385SBrandon     if (islite) {
441*5552b385SBrandon       PetscCall(EGlite_evaluate(obj, uvt, data));
442*5552b385SBrandon     } else {
443*5552b385SBrandon       PetscCall(EG_evaluate(obj, uvt, data));
444*5552b385SBrandon     }
445*5552b385SBrandon 
446*5552b385SBrandon     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]);
447*5552b385SBrandon 
448*5552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
449*5552b385SBrandon     if (obj_tmp < obj_old) {
450*5552b385SBrandon       obj_old = obj_tmp;
451*5552b385SBrandon       uvs[0]  = uvt[0];
452*5552b385SBrandon       uvs[1]  = uvt[1];
453*5552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
454*5552b385SBrandon       lambda /= 2.0;
455*5552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
456*5552b385SBrandon       if (obj_old < target) {
457*5552b385SBrandon         tolr = obj_old;
458*5552b385SBrandon         break;
459*5552b385SBrandon       }
460*5552b385SBrandon     } else {
461*5552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
462*5552b385SBrandon       lambda *= 2.0;
463*5552b385SBrandon     }
464*5552b385SBrandon 
465*5552b385SBrandon     if (sqrt(delta[0] * delta[0] + delta[1] * delta[1]) < target) {
466*5552b385SBrandon       tolr = obj_old;
467*5552b385SBrandon       break;
468*5552b385SBrandon     }
469*5552b385SBrandon 
470*5552b385SBrandon     tolr = obj_old;
471*5552b385SBrandon 
472*5552b385SBrandon     loopCntr += 1;
473*5552b385SBrandon     if (loopCntr > 100) break;
474*5552b385SBrandon   }
475*5552b385SBrandon   paramsV[v * 3 + 0] = uvs[0];
476*5552b385SBrandon   paramsV[v * 3 + 1] = uvs[1];
477*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
478*5552b385SBrandon }
479*5552b385SBrandon 
480*5552b385SBrandon PetscErrorCode DMSnapToGeomModel_EGADS_Internal(DM dm, PetscInt p, ego model, PetscInt bodyID, PetscInt faceID, PetscInt edgeID, const PetscScalar mcoords[], PetscScalar gcoords[], PetscBool islite)
481*5552b385SBrandon {
482*5552b385SBrandon   /* PETSc Variables */
483c1cad2e7SMatthew G. Knepley   DM   cdm;
484c1cad2e7SMatthew G. Knepley   ego *bodies;
485c1cad2e7SMatthew G. Knepley   ego  geom, body, obj;
486*5552b385SBrandon   /* result has to hold derviatives, along with the value */
487*5552b385SBrandon   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;
493*5552b385SBrandon   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));
499*5552b385SBrandon 
500*5552b385SBrandon   if (islite) {
501*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
502*5552b385SBrandon   } else {
5039566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
504*5552b385SBrandon   }
505*5552b385SBrandon 
506*5552b385SBrandon   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) {
510*5552b385SBrandon     if (islite) {
511*5552b385SBrandon       PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &obj));
512*5552b385SBrandon       Np = 1;
513*5552b385SBrandon     } else {
5149371c9d4SSatish Balay       PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &obj));
5159371c9d4SSatish Balay       Np = 1;
516*5552b385SBrandon     }
5179371c9d4SSatish Balay   } else if (faceID >= 0) {
518*5552b385SBrandon     if (islite) {
519*5552b385SBrandon       PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &obj));
520*5552b385SBrandon       Np = 2;
521*5552b385SBrandon     } else {
5229371c9d4SSatish Balay       PetscCall(EG_objectBodyTopo(body, FACE, faceID, &obj));
5239371c9d4SSatish Balay       Np = 2;
524*5552b385SBrandon     }
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 
540*5552b385SBrandon   /* Correct EGADS/EGADSlite 2pi bug when calculating nearest point on Periodic Surfaces */
541*5552b385SBrandon   if (islite) {
542*5552b385SBrandon     PetscCall(EGlite_getRange(obj, range, &peri));
543*5552b385SBrandon   } else {
5449566063dSJacob Faibussowitsch     PetscCall(EG_getRange(obj, range, &peri));
545*5552b385SBrandon   }
546*5552b385SBrandon 
547c1cad2e7SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
548*5552b385SBrandon     if (edgeID > 0) {
549*5552b385SBrandon       PetscCall(DMPlex_Geom_EDGE_XYZtoUV_Internal(coords, obj, range, v, dE, paramsV, islite));
550*5552b385SBrandon     } else {
551*5552b385SBrandon       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));
555*5552b385SBrandon 
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   }
562*5552b385SBrandon   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);
563*5552b385SBrandon   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);
564*5552b385SBrandon 
565c1cad2e7SMatthew G. Knepley   /* Put coordinates for new vertex in result[] */
566*5552b385SBrandon   if (islite) {
567*5552b385SBrandon     PetscCall(EGlite_evaluate(obj, params, result));
568*5552b385SBrandon   } else {
5699566063dSJacob Faibussowitsch     PetscCall(EG_evaluate(obj, params, result));
570*5552b385SBrandon   }
571*5552b385SBrandon 
572c1cad2e7SMatthew G. Knepley   for (d = 0; d < dE; ++d) gcoords[d] = result[d];
5733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
574c1cad2e7SMatthew G. Knepley }
575c1cad2e7SMatthew G. Knepley #endif
576c1cad2e7SMatthew G. Knepley 
5777625649eSMatthew G. Knepley PetscErrorCode DMSnapToGeomModel_EGADS(DM dm, PetscInt p, PetscInt dE, const PetscScalar mcoords[], PetscScalar gcoords[])
5787625649eSMatthew G. Knepley {
5797625649eSMatthew G. Knepley   PetscFunctionBeginHot;
5807625649eSMatthew G. Knepley #ifdef PETSC_HAVE_EGADS
5817625649eSMatthew G. Knepley   DMLabel        bodyLabel, faceLabel, edgeLabel;
5827625649eSMatthew G. Knepley   PetscInt       bodyID, faceID, edgeID;
5837625649eSMatthew G. Knepley   PetscContainer modelObj;
5847625649eSMatthew G. Knepley   ego            model;
585*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5867625649eSMatthew G. Knepley 
587*5552b385SBrandon   // 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));
593*5552b385SBrandon   if (!modelObj) {
594*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
595*5552b385SBrandon     islite = PETSC_TRUE;
596*5552b385SBrandon   }
5977625649eSMatthew G. Knepley   PetscCheck(modelObj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "EGADS mesh missing model object");
5987625649eSMatthew G. Knepley 
5997625649eSMatthew G. Knepley   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
6007625649eSMatthew G. Knepley   PetscCall(DMLabelGetValue(bodyLabel, p, &bodyID));
6017625649eSMatthew G. Knepley   PetscCall(DMLabelGetValue(faceLabel, p, &faceID));
6027625649eSMatthew G. Knepley   PetscCall(DMLabelGetValue(edgeLabel, p, &edgeID));
6037625649eSMatthew G. Knepley   /* Allows for "Connective" Plex Edges present in models with multiple non-touching Entities */
6047625649eSMatthew G. Knepley   if (bodyID < 0) {
6057625649eSMatthew G. Knepley     for (PetscInt d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
6067625649eSMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
6077625649eSMatthew G. Knepley   }
608*5552b385SBrandon   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)
614*5552b385SBrandon PetscErrorCode DMPlexGeomPrintModel_Internal(ego model, PetscBool islite)
615d71ae5a4SJacob Faibussowitsch {
616*5552b385SBrandon   /* PETSc Variables */
617*5552b385SBrandon   ego geom, *bodies, *nobjs, *mobjs, *lobjs, *shobjs, *fobjs, *eobjs;
618*5552b385SBrandon   int oclass, mtype, *senses, *shsenses, *fsenses, *lsenses, *esenses;
6197bee2925SMatthew Knepley   int Nb, b;
6207bee2925SMatthew Knepley 
6217bee2925SMatthew Knepley   PetscFunctionBeginUser;
6227bee2925SMatthew Knepley   /* test bodyTopo functions */
623*5552b385SBrandon   if (islite) {
624*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
625*5552b385SBrandon   } else {
6269566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
627*5552b385SBrandon   }
628*5552b385SBrandon   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];
632*5552b385SBrandon     int id, sh, Nsh, f, Nf, l, Nl, e, Ne, v, Nv;
633*5552b385SBrandon 
634*5552b385SBrandon     /* List Topology of Bodies */
635*5552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
636*5552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   BODY %d TOPOLOGY SUMMARY \n", b));
6377bee2925SMatthew Knepley 
6387bee2925SMatthew Knepley     /* Output Basic Model Topology */
639*5552b385SBrandon     if (islite) {
640*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, SHELL, &Nsh, &shobjs));
641*5552b385SBrandon     } else {
642*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, SHELL, &Nsh, &shobjs));
643*5552b385SBrandon     }
6449566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of SHELLS: %d \n", Nsh));
6457bee2925SMatthew Knepley 
646*5552b385SBrandon     if (islite) {
647*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
648*5552b385SBrandon     } else {
649*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
650*5552b385SBrandon     }
6519566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of FACES: %d \n", Nf));
6527bee2925SMatthew Knepley 
653*5552b385SBrandon     if (islite) {
654*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
655*5552b385SBrandon     } else {
6569566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
657*5552b385SBrandon     }
6589566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of LOOPS: %d \n", Nl));
6597bee2925SMatthew Knepley 
660*5552b385SBrandon     if (islite) {
661*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
662*5552b385SBrandon     } else {
663*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
664*5552b385SBrandon     }
6659566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of EDGES: %d \n", Ne));
6667bee2925SMatthew Knepley 
667*5552b385SBrandon     if (islite) {
668*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
669*5552b385SBrandon     } else {
670*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
671*5552b385SBrandon     }
6729566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of NODES: %d \n", Nv));
673*5552b385SBrandon 
674*5552b385SBrandon     if (islite) {
675*5552b385SBrandon       EGlite_free(shobjs);
676*5552b385SBrandon       EGlite_free(fobjs);
677*5552b385SBrandon       EGlite_free(lobjs);
678*5552b385SBrandon       EGlite_free(eobjs);
679*5552b385SBrandon       EGlite_free(nobjs);
680*5552b385SBrandon     } else {
681*5552b385SBrandon       EG_free(shobjs);
682*5552b385SBrandon       EG_free(fobjs);
683*5552b385SBrandon       EG_free(lobjs);
684*5552b385SBrandon       EG_free(eobjs);
685*5552b385SBrandon       EG_free(nobjs);
686*5552b385SBrandon     }
687*5552b385SBrandon 
688*5552b385SBrandon     /* List Topology of Bodies */
689*5552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
690*5552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      BODY %d TOPOLOGY DETAILS \n", b));
691*5552b385SBrandon 
692*5552b385SBrandon     /* Get SHELL info which associated with the current BODY */
693*5552b385SBrandon     if (islite) {
694*5552b385SBrandon       PetscCall(EGlite_getTopology(body, &geom, &oclass, &mtype, NULL, &Nsh, &shobjs, &shsenses));
695*5552b385SBrandon     } else {
696*5552b385SBrandon       PetscCall(EG_getTopology(body, &geom, &oclass, &mtype, NULL, &Nsh, &shobjs, &shsenses));
697*5552b385SBrandon     }
698*5552b385SBrandon 
699*5552b385SBrandon     for (sh = 0; sh < Nsh; ++sh) {
700*5552b385SBrandon       ego shell   = shobjs[sh];
701*5552b385SBrandon       int shsense = shsenses[sh];
702*5552b385SBrandon 
703*5552b385SBrandon       if (islite) {
704*5552b385SBrandon         id = EGlite_indexBodyTopo(body, shell);
705*5552b385SBrandon       } else {
706*5552b385SBrandon         id = EG_indexBodyTopo(body, shell);
707*5552b385SBrandon       }
708*5552b385SBrandon       PetscCall(PetscPrintf(PETSC_COMM_SELF, "         SHELL ID: %d :: sense = %d\n", id, shsense));
709*5552b385SBrandon 
710*5552b385SBrandon       /* Get FACE infor associated with current SHELL */
711*5552b385SBrandon       if (islite) {
712*5552b385SBrandon         PetscCall(EGlite_getTopology(shell, &geom, &oclass, &mtype, NULL, &Nf, &fobjs, &fsenses));
713*5552b385SBrandon       } else {
714*5552b385SBrandon         PetscCall(EG_getTopology(shell, &geom, &oclass, &mtype, NULL, &Nf, &fobjs, &fsenses));
715*5552b385SBrandon       }
716*5552b385SBrandon 
717*5552b385SBrandon       for (f = 0; f < Nf; ++f) {
718*5552b385SBrandon         ego     face = fobjs[f];
719*5552b385SBrandon         ego     gRef, gPrev, gNext;
720*5552b385SBrandon         int     goclass, gmtype, *gpinfo;
721*5552b385SBrandon         double *gprv;
722*5552b385SBrandon         char   *gClass = (char *)"", *gType = (char *)"";
723*5552b385SBrandon         double  fdata[4];
724*5552b385SBrandon         ego     fRef, fPrev, fNext;
725*5552b385SBrandon         int     foclass, fmtype;
726*5552b385SBrandon 
727*5552b385SBrandon         if (islite) {
728*5552b385SBrandon           id = EGlite_indexBodyTopo(body, face);
729*5552b385SBrandon         } else {
730*5552b385SBrandon           id = EG_indexBodyTopo(body, face);
731*5552b385SBrandon         }
732*5552b385SBrandon 
733*5552b385SBrandon         /* Get LOOP info associated with current FACE */
734*5552b385SBrandon         if (islite) {
735*5552b385SBrandon           PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, fdata, &Nl, &lobjs, &lsenses));
736*5552b385SBrandon           PetscCall(EGlite_getInfo(face, &foclass, &fmtype, &fRef, &fPrev, &fNext));
737*5552b385SBrandon           PetscCall(EGlite_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
738*5552b385SBrandon           PetscCall(EGlite_getInfo(geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
739*5552b385SBrandon         } else {
740*5552b385SBrandon           PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, fdata, &Nl, &lobjs, &lsenses));
741*5552b385SBrandon           PetscCall(EG_getInfo(face, &foclass, &fmtype, &fRef, &fPrev, &fNext));
742*5552b385SBrandon           PetscCall(EG_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
743*5552b385SBrandon           PetscCall(EG_getInfo(geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
744*5552b385SBrandon         }
745*5552b385SBrandon 
746*5552b385SBrandon         PetscCall(DMPlex_EGADS_GeomDecode_Internal(goclass, gmtype, &gClass, &gType));
747*5552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "           FACE ID: %d :: sense = %d \n", id, fmtype));
748*5552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "             GEOMETRY CLASS: %s \n", gClass));
749*5552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "             GEOMETRY TYPE:  %s \n\n", gType));
750*5552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "             RANGE (umin, umax) = (%f, %f) \n", fdata[0], fdata[1]));
751*5552b385SBrandon         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];
755*5552b385SBrandon           int lsense = lsenses[l];
7567bee2925SMatthew Knepley 
757*5552b385SBrandon           if (islite) {
758*5552b385SBrandon             id = EGlite_indexBodyTopo(body, loop);
759*5552b385SBrandon           } else {
7607bee2925SMatthew Knepley             id = EG_indexBodyTopo(body, loop);
761*5552b385SBrandon           }
7627bee2925SMatthew Knepley 
763*5552b385SBrandon           PetscCall(PetscPrintf(PETSC_COMM_SELF, "             LOOP ID: %d :: sense = %d\n", id, lsense));
764*5552b385SBrandon 
765*5552b385SBrandon           /* Get EDGE info associated with the current LOOP */
766*5552b385SBrandon           if (islite) {
767*5552b385SBrandon             PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &esenses));
768*5552b385SBrandon           } else {
769*5552b385SBrandon             PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &esenses));
770*5552b385SBrandon           }
7717bee2925SMatthew Knepley 
7727bee2925SMatthew Knepley           for (e = 0; e < Ne; ++e) {
773*5552b385SBrandon             ego    edge = eobjs[e];
774*5552b385SBrandon             ego    topRef, prev, next;
775*5552b385SBrandon             int    esense   = esenses[e];
7767bee2925SMatthew Knepley             double range[4] = {0., 0., 0., 0.};
7777bee2925SMatthew Knepley             int    peri;
778*5552b385SBrandon             ego    gEref, gEprev, gEnext;
779*5552b385SBrandon             int    gEoclass, gEmtype;
780*5552b385SBrandon             char  *gEclass = (char *)"", *gEtype = (char *)"";
7817bee2925SMatthew Knepley 
782*5552b385SBrandon             if (islite) {
783*5552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
784*5552b385SBrandon               if (mtype != DEGENERATE) { PetscCall(EGlite_getInfo(geom, &gEoclass, &gEmtype, &gEref, &gEprev, &gEnext)); }
785266cfabeSMatthew G. Knepley             } else {
786*5552b385SBrandon               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
787*5552b385SBrandon               PetscCall(EG_getInfo(geom, &gEoclass, &gEmtype, &gEref, &gEprev, &gEnext));
788*5552b385SBrandon             }
789*5552b385SBrandon 
790*5552b385SBrandon             if (mtype != DEGENERATE) { PetscCall(DMPlex_EGADS_GeomDecode_Internal(gEoclass, gEmtype, &gEclass, &gEtype)); }
791*5552b385SBrandon 
792*5552b385SBrandon             if (islite) {
793*5552b385SBrandon               id = EGlite_indexBodyTopo(body, edge);
794*5552b385SBrandon               PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
795*5552b385SBrandon             } else {
796*5552b385SBrandon               id = EG_indexBodyTopo(body, edge);
797*5552b385SBrandon               PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
798*5552b385SBrandon             }
799*5552b385SBrandon 
800*5552b385SBrandon             PetscCall(PetscPrintf(PETSC_COMM_SELF, "               EDGE ID: %d :: sense = %d\n", id, esense));
801*5552b385SBrandon             if (mtype != DEGENERATE) {
802*5552b385SBrandon               PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 GEOMETRY CLASS: %s \n", gEclass));
803*5552b385SBrandon               PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 GEOMETRY TYPE:  %s \n", gEtype));
804*5552b385SBrandon             }
805*5552b385SBrandon 
806*5552b385SBrandon             if (mtype == DEGENERATE) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 EDGE %d is DEGENERATE \n", id)); }
807*5552b385SBrandon 
808*5552b385SBrandon             if (islite) {
809*5552b385SBrandon               PetscCall(EGlite_getRange(edge, range, &peri));
810*5552b385SBrandon             } else {
811*5552b385SBrandon               PetscCall(EG_getRange(edge, range, &peri));
812*5552b385SBrandon             }
813*5552b385SBrandon 
814*5552b385SBrandon             PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 Peri = %d :: Range = %lf, %lf, %lf, %lf \n", peri, range[0], range[1], range[2], range[3]));
815*5552b385SBrandon 
816*5552b385SBrandon             /* Get NODE info associated with the current EDGE */
817*5552b385SBrandon             if (islite) {
818*5552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
819*5552b385SBrandon             } else {
820*5552b385SBrandon               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
821266cfabeSMatthew G. Knepley             }
8227bee2925SMatthew Knepley 
8237bee2925SMatthew Knepley             for (v = 0; v < Nv; ++v) {
8247bee2925SMatthew Knepley               ego    vertex = nobjs[v];
8257bee2925SMatthew Knepley               double limits[4];
8267bee2925SMatthew Knepley               int    dummy;
8277bee2925SMatthew Knepley 
828*5552b385SBrandon               if (islite) {
829*5552b385SBrandon                 PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
830*5552b385SBrandon                 id = EGlite_indexBodyTopo(body, vertex);
831*5552b385SBrandon               } else {
8329566063dSJacob Faibussowitsch                 PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
8337bee2925SMatthew Knepley                 id = EG_indexBodyTopo(body, vertex);
834*5552b385SBrandon               }
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       }
841*5552b385SBrandon     }
842*5552b385SBrandon   }
843*5552b385SBrandon   PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n\n"));
8443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8457bee2925SMatthew Knepley }
8467bee2925SMatthew Knepley 
84749abdd8aSBarry Smith static PetscErrorCode DMPlexEGADSDestroy_Private(void **context)
848d71ae5a4SJacob Faibussowitsch {
849*5552b385SBrandon   if (*context) EG_deleteObject((ego)*context);
850*5552b385SBrandon   return (PETSC_SUCCESS);
851*5552b385SBrandon }
852*5552b385SBrandon 
853*5552b385SBrandon static PetscErrorCode DMPlexEGADSClose_Private(void **context)
854*5552b385SBrandon {
855*5552b385SBrandon   if (*context) EG_close((ego)*context);
856*5552b385SBrandon   return (PETSC_SUCCESS);
857*5552b385SBrandon }
858*5552b385SBrandon 
859*5552b385SBrandon PetscErrorCode DMPlexEGADSliteDestroy_Private(void **context)
860*5552b385SBrandon {
861*5552b385SBrandon   if (*context) EGlite_deleteObject((ego)*context);
8627bee2925SMatthew Knepley   return 0;
8637bee2925SMatthew Knepley }
8647bee2925SMatthew Knepley 
865*5552b385SBrandon PetscErrorCode DMPlexEGADSliteClose_Private(void **context)
866d71ae5a4SJacob Faibussowitsch {
867*5552b385SBrandon   if (*context) EGlite_close((ego)*context);
868*5552b385SBrandon   return 0;
869*5552b385SBrandon }
870*5552b385SBrandon 
871*5552b385SBrandon PetscErrorCode DMPlexCreateGeom_Internal(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
872*5552b385SBrandon {
873*5552b385SBrandon   /* 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;
879*5552b385SBrandon   DMLabel     bodyLabel, faceLabel, edgeLabel, vertexLabel;
8807bee2925SMatthew Knepley   PetscHMapI  edgeMap = NULL;
881*5552b385SBrandon   PetscInt    cStart, cEnd, c;
8827bee2925SMatthew Knepley   PetscInt    dim = -1, cdim = -1, numCorners = 0, maxCorners = 0, numVertices = 0, newVertices = 0, numEdges = 0, numCells = 0, newCells = 0, numQuads = 0, cOff = 0, fOff = 0;
8837bee2925SMatthew Knepley   PetscInt   *cells = NULL, *cone = NULL;
8847bee2925SMatthew Knepley   PetscReal  *coords = NULL;
8857bee2925SMatthew Knepley   PetscMPIInt rank;
8867bee2925SMatthew Knepley 
8877bee2925SMatthew Knepley   PetscFunctionBegin;
8889566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
889dd400576SPatrick Sanan   if (rank == 0) {
890266cfabeSMatthew G. Knepley     const PetscInt debug = 0;
891266cfabeSMatthew G. Knepley 
8927bee2925SMatthew Knepley     /* ---------------------------------------------------------------------------------------------------
8937bee2925SMatthew Knepley     Generate Petsc Plex
8947bee2925SMatthew Knepley       Get all Nodes in model, record coordinates in a correctly formatted array
8957bee2925SMatthew Knepley       Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
8967bee2925SMatthew Knepley       We need to uniformly refine the initial geometry to guarantee a valid mesh
8977bee2925SMatthew Knepley     */
8987bee2925SMatthew Knepley 
8997bee2925SMatthew Knepley     /* Calculate cell and vertex sizes */
900*5552b385SBrandon     if (islite) {
901*5552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
902*5552b385SBrandon     } else {
9039566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
904*5552b385SBrandon     }
905*5552b385SBrandon 
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 
912*5552b385SBrandon       if (islite) {
913*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
914*5552b385SBrandon       } else {
9159566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
916*5552b385SBrandon       }
917*5552b385SBrandon 
9187bee2925SMatthew Knepley       for (l = 0; l < Nl; ++l) {
9197bee2925SMatthew Knepley         ego loop = lobjs[l];
9207bee2925SMatthew Knepley         int Ner  = 0, Ne, e, Nc;
9217bee2925SMatthew Knepley 
922*5552b385SBrandon         if (islite) {
923*5552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
924*5552b385SBrandon         } else {
9259566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
926*5552b385SBrandon         }
927*5552b385SBrandon 
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 
934*5552b385SBrandon           if (islite) {
935*5552b385SBrandon             PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
936*5552b385SBrandon           } else {
9379566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
938*5552b385SBrandon           }
939*5552b385SBrandon 
9407bee2925SMatthew Knepley           if (mtype == DEGENERATE) continue;
941*5552b385SBrandon 
942*5552b385SBrandon           if (islite) {
943*5552b385SBrandon             id = EGlite_indexBodyTopo(body, edge);
944*5552b385SBrandon           } else {
9455f80ce2aSJacob Faibussowitsch             id = EG_indexBodyTopo(body, edge);
946*5552b385SBrandon           }
947*5552b385SBrandon 
9489566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(edgeMap, id - 1, &iter, &found));
949*5552b385SBrandon           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       }
964*5552b385SBrandon       if (islite) {
965*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
966*5552b385SBrandon       } else {
9679566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
968*5552b385SBrandon       }
969*5552b385SBrandon 
9707bee2925SMatthew Knepley       for (v = 0; v < Nv; ++v) {
9717bee2925SMatthew Knepley         ego vertex = nobjs[v];
9727bee2925SMatthew Knepley 
973*5552b385SBrandon         if (islite) {
974*5552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
975*5552b385SBrandon         } else {
9767bee2925SMatthew Knepley           id = EG_indexBodyTopo(body, vertex);
977*5552b385SBrandon         }
9787bee2925SMatthew Knepley         /* TODO: Instead of assuming contiguous ids, we could use a hash table */
9797bee2925SMatthew Knepley         numVertices = PetscMax(id, numVertices);
9807bee2925SMatthew Knepley       }
981*5552b385SBrandon       if (islite) {
982*5552b385SBrandon         EGlite_free(lobjs);
983*5552b385SBrandon         EGlite_free(nobjs);
984*5552b385SBrandon       } else {
9857bee2925SMatthew Knepley         EG_free(lobjs);
9867bee2925SMatthew Knepley         EG_free(nobjs);
9877bee2925SMatthew Knepley       }
988*5552b385SBrandon     }
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 
1003*5552b385SBrandon       if (islite) {
1004*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1005*5552b385SBrandon       } else {
10069566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1007*5552b385SBrandon       }
1008*5552b385SBrandon 
10097bee2925SMatthew Knepley       for (v = 0; v < Nv; ++v) {
10107bee2925SMatthew Knepley         ego    vertex = nobjs[v];
10117bee2925SMatthew Knepley         double limits[4];
10127bee2925SMatthew Knepley         int    dummy;
10137bee2925SMatthew Knepley 
1014*5552b385SBrandon         if (islite) {
1015*5552b385SBrandon           PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
1016*5552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
1017*5552b385SBrandon         } else {
10189566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
10195f80ce2aSJacob Faibussowitsch           id = EG_indexBodyTopo(body, vertex);
1020*5552b385SBrandon         }
1021*5552b385SBrandon 
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       }
1026*5552b385SBrandon       if (islite) {
1027*5552b385SBrandon         EGlite_free(nobjs);
1028*5552b385SBrandon       } else {
10297bee2925SMatthew Knepley         EG_free(nobjs);
10307bee2925SMatthew Knepley       }
1031*5552b385SBrandon     }
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 
1040*5552b385SBrandon       if (islite) {
1041*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
1042*5552b385SBrandon       } else {
10439566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
1044*5552b385SBrandon       }
1045*5552b385SBrandon 
10467bee2925SMatthew Knepley       for (l = 0; l < Nl; ++l) {
10477bee2925SMatthew Knepley         ego loop = lobjs[l];
10487bee2925SMatthew Knepley         int lid, Ner = 0, Ne, e;
10497bee2925SMatthew Knepley 
1050*5552b385SBrandon         if (islite) {
1051*5552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
1052*5552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
1053*5552b385SBrandon         } else {
10545f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
10559566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
1056*5552b385SBrandon         }
1057*5552b385SBrandon 
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 
1064*5552b385SBrandon           if (islite) {
1065*5552b385SBrandon             PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1066*5552b385SBrandon           } else {
10679566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1068*5552b385SBrandon           }
1069*5552b385SBrandon 
10707bee2925SMatthew Knepley           if (mtype == DEGENERATE) continue;
10717bee2925SMatthew Knepley           ++Ner;
1072*5552b385SBrandon 
1073*5552b385SBrandon           if (islite) {
1074*5552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
1075*5552b385SBrandon           } else {
10765f80ce2aSJacob Faibussowitsch             eid = EG_indexBodyTopo(body, edge);
1077*5552b385SBrandon           }
1078*5552b385SBrandon 
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++));
1086*5552b385SBrandon 
1087*5552b385SBrandon             if (islite) {
1088*5552b385SBrandon               PetscCall(EGlite_getRange(edge, range, periodic));
1089*5552b385SBrandon             } else {
10909566063dSJacob Faibussowitsch               PetscCall(EG_getRange(edge, range, periodic));
1091*5552b385SBrandon             }
1092*5552b385SBrandon 
10937bee2925SMatthew Knepley             params[0] = 0.5 * (range[0] + range[1]);
1094*5552b385SBrandon             if (islite) {
1095*5552b385SBrandon               PetscCall(EGlite_evaluate(edge, params, result));
1096*5552b385SBrandon             } else {
10979566063dSJacob Faibussowitsch               PetscCall(EG_evaluate(edge, params, result));
1098*5552b385SBrandon             }
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 
1110*5552b385SBrandon           if (islite) {
1111*5552b385SBrandon             PetscCall(EGlite_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
1112*5552b385SBrandon           } else {
11139566063dSJacob Faibussowitsch             PetscCall(EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
1114*5552b385SBrandon           }
1115266cfabeSMatthew G. Knepley           face = fobjs[0];
1116*5552b385SBrandon 
1117*5552b385SBrandon           if (islite) {
1118*5552b385SBrandon             fid = EGlite_indexBodyTopo(body, face);
1119*5552b385SBrandon           } else {
11205f80ce2aSJacob Faibussowitsch             fid = EG_indexBodyTopo(body, face);
1121*5552b385SBrandon           }
1122*5552b385SBrandon 
1123*5552b385SBrandon           PetscCheck(Nf != 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Loop %d has %" PetscInt_FMT " faces, instead of 1 (%" PetscInt_FMT ")", lid - 1, Nf, fid);
1124*5552b385SBrandon           if (islite) {
1125*5552b385SBrandon             PetscCall(EGlite_getRange(face, range, periodic));
1126*5552b385SBrandon           } else {
11279566063dSJacob Faibussowitsch             PetscCall(EG_getRange(face, range, periodic));
1128*5552b385SBrandon           }
11297bee2925SMatthew Knepley           params[0] = 0.5 * (range[0] + range[1]);
11307bee2925SMatthew Knepley           params[1] = 0.5 * (range[2] + range[3]);
1131*5552b385SBrandon           if (islite) {
1132*5552b385SBrandon             PetscCall(EGlite_evaluate(face, params, result));
1133*5552b385SBrandon           } else {
11349566063dSJacob Faibussowitsch             PetscCall(EG_evaluate(face, params, result));
1135*5552b385SBrandon           }
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     }
1142*5552b385SBrandon     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 
1151*5552b385SBrandon       if (islite) {
1152*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
1153*5552b385SBrandon       } else {
11549566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
1155*5552b385SBrandon       }
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 
1160*5552b385SBrandon         if (islite) {
1161*5552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
1162*5552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
1163*5552b385SBrandon         } else {
11645f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
11659566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
1166*5552b385SBrandon         }
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 
1173*5552b385SBrandon           if (islite) {
1174*5552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
1175*5552b385SBrandon             PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1176*5552b385SBrandon           } else {
11777bee2925SMatthew Knepley             eid = EG_indexBodyTopo(body, edge);
11789566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1179*5552b385SBrandon           }
1180*5552b385SBrandon 
1181266cfabeSMatthew G. Knepley           if (mtype == DEGENERATE) continue;
1182266cfabeSMatthew G. Knepley           else ++Ner;
1183*5552b385SBrandon           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 
1188*5552b385SBrandon             if (islite) {
1189*5552b385SBrandon               id = EGlite_indexBodyTopo(body, vertex);
1190*5552b385SBrandon             } else {
11917bee2925SMatthew Knepley               id = EG_indexBodyTopo(body, vertex);
1192*5552b385SBrandon             }
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);
1227*5552b385SBrandon         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) {
1301*5552b385SBrandon             PetscCall(PetscPrintf(PETSC_COMM_SELF, "  LOOP Corner NODEs Triangle %d (", t));
13027bee2925SMatthew Knepley             for (c = 0; c < numCorners; ++c) {
1303*5552b385SBrandon               if (c > 0) { PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); }
1304*5552b385SBrandon               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       }
1310*5552b385SBrandon       if (islite) {
1311*5552b385SBrandon         EGlite_free(lobjs);
1312*5552b385SBrandon       } else {
13137bee2925SMatthew Knepley         EG_free(lobjs);
13147bee2925SMatthew Knepley       }
13157bee2925SMatthew Knepley     }
1316*5552b385SBrandon   }
1317*5552b385SBrandon   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));
1320*5552b385SBrandon   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %d (%d)\n", numCells, newCells));
1321*5552b385SBrandon   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));
1328*5552b385SBrandon     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));
1334*5552b385SBrandon     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 
1352*5552b385SBrandon     if (islite) {
1353*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
1354*5552b385SBrandon     } else {
13559566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
1356*5552b385SBrandon     }
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 
1362*5552b385SBrandon       if (islite) {
1363*5552b385SBrandon         lid = EGlite_indexBodyTopo(body, loop);
1364*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
1365*5552b385SBrandon       } else {
13665f80ce2aSJacob Faibussowitsch         lid = EG_indexBodyTopo(body, loop);
13679566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
1368*5552b385SBrandon       }
1369*5552b385SBrandon 
137008401ef6SPierre Jolivet       PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d > 1 faces, which is not supported", lid, Nf);
1371*5552b385SBrandon       if (islite) {
1372*5552b385SBrandon         fid = EGlite_indexBodyTopo(body, fobjs[0]);
1373*5552b385SBrandon         EGlite_free(fobjs);
1374*5552b385SBrandon         PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
1375*5552b385SBrandon       } 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));
1379*5552b385SBrandon       }
1380*5552b385SBrandon 
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 
1387*5552b385SBrandon         if (islite) {
1388*5552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
1389*5552b385SBrandon           PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1390*5552b385SBrandon         } else {
13917bee2925SMatthew Knepley           eid = EG_indexBodyTopo(body, edge);
13929566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1393*5552b385SBrandon         }
1394*5552b385SBrandon 
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 
1400*5552b385SBrandon           if (islite) {
1401*5552b385SBrandon             id = EGlite_indexBodyTopo(body, vertex);
1402*5552b385SBrandon           } else {
14037bee2925SMatthew Knepley             id = EG_indexBodyTopo(body, vertex);
1404*5552b385SBrandon           }
1405*5552b385SBrandon 
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));
1416*5552b385SBrandon         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));
1422*5552b385SBrandon         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     }
1445*5552b385SBrandon     if (islite) {
1446*5552b385SBrandon       EGlite_free(lobjs);
1447*5552b385SBrandon     } else {
14487bee2925SMatthew Knepley       EG_free(lobjs);
14497bee2925SMatthew Knepley     }
1450*5552b385SBrandon   }
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;
1467*5552b385SBrandon   PetscFunctionReturn(0);
14687bee2925SMatthew Knepley }
1469c1cad2e7SMatthew G. Knepley 
1470*5552b385SBrandon PetscErrorCode DMPlexCreateGeom(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
1471d71ae5a4SJacob Faibussowitsch {
1472*5552b385SBrandon   // 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;
1479*5552b385SBrandon   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
1480c1cad2e7SMatthew G. Knepley   PetscHMapI      edgeMap = NULL, bodyIndexMap = NULL, bodyVertexMap = NULL, bodyEdgeMap = NULL, bodyFaceMap = NULL, bodyEdgeGlobalMap = NULL;
1481c1cad2e7SMatthew G. Knepley   PetscInt        dim = -1, cdim = -1, numCorners = 0, numVertices = 0, numEdges = 0, numFaces = 0, numCells = 0, edgeCntr = 0;
1482c1cad2e7SMatthew G. Knepley   PetscInt        cellCntr = 0, numPoints = 0;
1483c1cad2e7SMatthew G. Knepley   PetscInt       *cells  = NULL;
1484c1cad2e7SMatthew G. Knepley   const PetscInt *cone   = NULL;
1485c1cad2e7SMatthew G. Knepley   PetscReal      *coords = NULL;
1486c1cad2e7SMatthew G. Knepley   PetscMPIInt     rank;
1487c1cad2e7SMatthew G. Knepley 
1488c1cad2e7SMatthew G. Knepley   PetscFunctionBeginUser;
14899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1490c5853193SPierre Jolivet   if (rank == 0) {
1491c1cad2e7SMatthew G. Knepley     // ---------------------------------------------------------------------------------------------------
1492c1cad2e7SMatthew G. Knepley     // Generate Petsc Plex
1493c1cad2e7SMatthew G. Knepley     //  Get all Nodes in model, record coordinates in a correctly formatted array
1494c1cad2e7SMatthew G. Knepley     //  Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
1495c1cad2e7SMatthew G. Knepley     //  We need to uniformly refine the initial geometry to guarantee a valid mesh
1496c1cad2e7SMatthew G. Knepley 
1497d5b43468SJose E. Roman     // Calculate cell and vertex sizes
1498*5552b385SBrandon     if (islite) {
1499*5552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
1500*5552b385SBrandon     } else {
15019566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
1502*5552b385SBrandon     }
15039566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&edgeMap));
15049566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyIndexMap));
15059566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyVertexMap));
15069566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyEdgeMap));
15079566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyEdgeGlobalMap));
15089566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyFaceMap));
1509c1cad2e7SMatthew G. Knepley 
1510c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
1511c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
1512c1cad2e7SMatthew G. Knepley       int           Nf, Ne, Nv;
1513c1cad2e7SMatthew G. Knepley       PetscHashIter BIiter, BViter, BEiter, BEGiter, BFiter, EMiter;
1514c1cad2e7SMatthew G. Knepley       PetscBool     BIfound, BVfound, BEfound, BEGfound, BFfound, EMfound;
1515c1cad2e7SMatthew G. Knepley 
15169566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyIndexMap, b, &BIiter, &BIfound));
15179566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
15189566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
15199566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
15209566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
1521c1cad2e7SMatthew G. Knepley 
15229566063dSJacob Faibussowitsch       if (!BIfound) PetscCall(PetscHMapISet(bodyIndexMap, b, numFaces + numEdges + numVertices));
15239566063dSJacob Faibussowitsch       if (!BVfound) PetscCall(PetscHMapISet(bodyVertexMap, b, numVertices));
15249566063dSJacob Faibussowitsch       if (!BEfound) PetscCall(PetscHMapISet(bodyEdgeMap, b, numEdges));
15259566063dSJacob Faibussowitsch       if (!BEGfound) PetscCall(PetscHMapISet(bodyEdgeGlobalMap, b, edgeCntr));
15269566063dSJacob Faibussowitsch       if (!BFfound) PetscCall(PetscHMapISet(bodyFaceMap, b, numFaces));
1527c1cad2e7SMatthew G. Knepley 
1528*5552b385SBrandon       if (islite) {
1529*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1530*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
1531*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1532*5552b385SBrandon         EGlite_free(fobjs);
1533*5552b385SBrandon         EGlite_free(eobjs);
1534*5552b385SBrandon         EGlite_free(nobjs);
1535*5552b385SBrandon       } else {
15369566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15389566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1539c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1540c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
1541c1cad2e7SMatthew G. Knepley         EG_free(nobjs);
1542*5552b385SBrandon       }
1543c1cad2e7SMatthew G. Knepley 
1544c1cad2e7SMatthew G. Knepley       // Remove DEGENERATE EDGES from Edge count
1545*5552b385SBrandon       if (islite) {
1546*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
1547*5552b385SBrandon       } else {
15489566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
1549*5552b385SBrandon       }
1550*5552b385SBrandon 
1551c1cad2e7SMatthew G. Knepley       int Netemp = 0;
1552c1cad2e7SMatthew G. Knepley       for (int e = 0; e < Ne; ++e) {
1553c1cad2e7SMatthew G. Knepley         ego edge = eobjs[e];
1554c1cad2e7SMatthew G. Knepley         int eid;
1555c1cad2e7SMatthew G. Knepley 
1556*5552b385SBrandon         if (islite) {
1557*5552b385SBrandon           PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1558*5552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
1559*5552b385SBrandon         } else {
15609566063dSJacob Faibussowitsch           PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
15615f80ce2aSJacob Faibussowitsch           eid = EG_indexBodyTopo(body, edge);
1562*5552b385SBrandon         }
1563c1cad2e7SMatthew G. Knepley 
15649566063dSJacob Faibussowitsch         PetscCall(PetscHMapIFind(edgeMap, edgeCntr + eid - 1, &EMiter, &EMfound));
1565c1cad2e7SMatthew G. Knepley         if (mtype == DEGENERATE) {
15669566063dSJacob Faibussowitsch           if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, -1));
15679371c9d4SSatish Balay         } else {
1568c1cad2e7SMatthew G. Knepley           ++Netemp;
15699566063dSJacob Faibussowitsch           if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, Netemp));
1570c1cad2e7SMatthew G. Knepley         }
1571c1cad2e7SMatthew G. Knepley       }
1572*5552b385SBrandon       if (islite) {
1573*5552b385SBrandon         EGlite_free(eobjs);
1574*5552b385SBrandon       } else {
1575c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
1576*5552b385SBrandon       }
1577c1cad2e7SMatthew G. Knepley 
1578c1cad2e7SMatthew G. Knepley       // Determine Number of Cells
1579*5552b385SBrandon       if (islite) {
1580*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1581*5552b385SBrandon       } else {
15829566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1583*5552b385SBrandon       }
1584*5552b385SBrandon 
1585c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1586c1cad2e7SMatthew G. Knepley         ego face     = fobjs[f];
1587c1cad2e7SMatthew G. Knepley         int edgeTemp = 0;
1588c1cad2e7SMatthew G. Knepley 
1589*5552b385SBrandon         if (islite) {
1590*5552b385SBrandon           PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
1591*5552b385SBrandon         } else {
15929566063dSJacob Faibussowitsch           PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
1593*5552b385SBrandon         }
1594*5552b385SBrandon 
1595c1cad2e7SMatthew G. Knepley         for (int e = 0; e < Ne; ++e) {
1596c1cad2e7SMatthew G. Knepley           ego edge = eobjs[e];
1597c1cad2e7SMatthew G. Knepley 
1598*5552b385SBrandon           if (islite) {
1599*5552b385SBrandon             PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1600*5552b385SBrandon           } else {
16019566063dSJacob Faibussowitsch             PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1602*5552b385SBrandon           }
1603ad540459SPierre Jolivet           if (mtype != DEGENERATE) ++edgeTemp;
1604c1cad2e7SMatthew G. Knepley         }
1605c1cad2e7SMatthew G. Knepley         numCells += (2 * edgeTemp);
1606*5552b385SBrandon         if (islite) {
1607*5552b385SBrandon           EGlite_free(eobjs);
1608*5552b385SBrandon         } else {
1609c1cad2e7SMatthew G. Knepley           EG_free(eobjs);
1610c1cad2e7SMatthew G. Knepley         }
1611*5552b385SBrandon       }
1612*5552b385SBrandon       if (islite) {
1613*5552b385SBrandon         EGlite_free(fobjs);
1614*5552b385SBrandon       } else {
1615c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1616*5552b385SBrandon       }
1617c1cad2e7SMatthew G. Knepley 
1618c1cad2e7SMatthew G. Knepley       numFaces += Nf;
1619c1cad2e7SMatthew G. Knepley       numEdges += Netemp;
1620c1cad2e7SMatthew G. Knepley       numVertices += Nv;
1621c1cad2e7SMatthew G. Knepley       edgeCntr += Ne;
1622c1cad2e7SMatthew G. Knepley     }
1623c1cad2e7SMatthew G. Knepley 
1624c1cad2e7SMatthew G. Knepley     // Set up basic DMPlex parameters
162535cb6cd3SPierre Jolivet     dim        = 2;                                 // Assumes 3D Models :: Need to handle 2D models in the future
162635cb6cd3SPierre Jolivet     cdim       = 3;                                 // Assumes 3D Models :: Need to update to handle 2D models in future
1627c1cad2e7SMatthew G. Knepley     numCorners = 3;                                 // Split Faces into triangles
1628c1cad2e7SMatthew G. Knepley     numPoints  = numVertices + numEdges + numFaces; // total number of coordinate points
1629c1cad2e7SMatthew G. Knepley 
16309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPoints * cdim, &coords, numCells * numCorners, &cells));
1631c1cad2e7SMatthew G. Knepley 
1632c1cad2e7SMatthew G. Knepley     // Get Vertex Coordinates and Set up Cells
1633c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
1634c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
1635c1cad2e7SMatthew G. Knepley       int           Nf, Ne, Nv;
1636c1cad2e7SMatthew G. Knepley       PetscInt      bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
1637c1cad2e7SMatthew G. Knepley       PetscHashIter BViter, BEiter, BEGiter, BFiter, EMiter;
1638c1cad2e7SMatthew G. Knepley       PetscBool     BVfound, BEfound, BEGfound, BFfound, EMfound;
1639c1cad2e7SMatthew G. Knepley 
1640c1cad2e7SMatthew G. Knepley       // Vertices on Current Body
1641*5552b385SBrandon       if (islite) {
1642*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1643*5552b385SBrandon       } else {
16449566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1645*5552b385SBrandon       }
1646c1cad2e7SMatthew G. Knepley 
16479566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
1648*5552b385SBrandon       PetscCheck(BVfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyVertexMap", b);
16499566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
1650c1cad2e7SMatthew G. Knepley 
1651c1cad2e7SMatthew G. Knepley       for (int v = 0; v < Nv; ++v) {
1652c1cad2e7SMatthew G. Knepley         ego    vertex = nobjs[v];
1653c1cad2e7SMatthew G. Knepley         double limits[4];
1654c1cad2e7SMatthew G. Knepley         int    id, dummy;
1655c1cad2e7SMatthew G. Knepley 
1656*5552b385SBrandon         if (islite) {
1657*5552b385SBrandon           PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
1658*5552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
1659*5552b385SBrandon         } else {
16609566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
16615f80ce2aSJacob Faibussowitsch           id = EG_indexBodyTopo(body, vertex);
1662*5552b385SBrandon         }
1663c1cad2e7SMatthew G. Knepley 
1664c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 0] = limits[0];
1665c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 1] = limits[1];
1666c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 2] = limits[2];
1667c1cad2e7SMatthew G. Knepley       }
1668*5552b385SBrandon       if (islite) {
1669*5552b385SBrandon         EGlite_free(nobjs);
1670*5552b385SBrandon       } else {
1671c1cad2e7SMatthew G. Knepley         EG_free(nobjs);
1672*5552b385SBrandon       }
1673c1cad2e7SMatthew G. Knepley 
1674c1cad2e7SMatthew G. Knepley       // Edge Midpoint Vertices on Current Body
1675*5552b385SBrandon       if (islite) {
1676*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
1677*5552b385SBrandon       } else {
16789566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
1679*5552b385SBrandon       }
1680c1cad2e7SMatthew G. Knepley 
16819566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
1682*5552b385SBrandon       PetscCheck(BEfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyEdgeMap", b);
16839566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
1684c1cad2e7SMatthew G. Knepley 
16859566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
1686*5552b385SBrandon       PetscCheck(BEGfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyEdgeGlobalMap", b);
16879566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
1688c1cad2e7SMatthew G. Knepley 
1689c1cad2e7SMatthew G. Knepley       for (int e = 0; e < Ne; ++e) {
1690c1cad2e7SMatthew G. Knepley         ego    edge = eobjs[e];
1691c1cad2e7SMatthew G. Knepley         double range[2], avgt[1], cntrPnt[9];
1692c1cad2e7SMatthew G. Knepley         int    eid, eOffset;
1693c1cad2e7SMatthew G. Knepley         int    periodic;
1694c1cad2e7SMatthew G. Knepley 
1695*5552b385SBrandon         if (islite) {
1696*5552b385SBrandon           PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1697*5552b385SBrandon         } else {
16989566063dSJacob Faibussowitsch           PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1699*5552b385SBrandon         }
1700ad540459SPierre Jolivet         if (mtype == DEGENERATE) continue;
1701c1cad2e7SMatthew G. Knepley 
1702*5552b385SBrandon         if (islite) {
1703*5552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
1704*5552b385SBrandon         } else {
17055f80ce2aSJacob Faibussowitsch           eid = EG_indexBodyTopo(body, edge);
1706*5552b385SBrandon         }
1707c1cad2e7SMatthew G. Knepley         // get relative offset from globalEdgeID Vector
17089566063dSJacob Faibussowitsch         PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
1709*5552b385SBrandon         PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " not found in edgeMap", bodyEdgeGlobalIndexStart + eid - 1);
17109566063dSJacob Faibussowitsch         PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1711c1cad2e7SMatthew G. Knepley 
1712*5552b385SBrandon         if (islite) {
1713*5552b385SBrandon           PetscCall(EGlite_getRange(edge, range, &periodic));
1714*5552b385SBrandon         } else {
17159566063dSJacob Faibussowitsch           PetscCall(EG_getRange(edge, range, &periodic));
1716*5552b385SBrandon         }
1717c1cad2e7SMatthew G. Knepley         avgt[0] = (range[0] + range[1]) / 2.;
1718c1cad2e7SMatthew G. Knepley 
1719*5552b385SBrandon         if (islite) {
1720*5552b385SBrandon           PetscCall(EGlite_evaluate(edge, avgt, cntrPnt));
1721*5552b385SBrandon         } else {
17229566063dSJacob Faibussowitsch           PetscCall(EG_evaluate(edge, avgt, cntrPnt));
1723*5552b385SBrandon         }
1724c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 0] = cntrPnt[0];
1725c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 1] = cntrPnt[1];
1726c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 2] = cntrPnt[2];
1727c1cad2e7SMatthew G. Knepley       }
1728*5552b385SBrandon       if (islite) {
1729*5552b385SBrandon         EGlite_free(eobjs);
1730*5552b385SBrandon       } else {
1731c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
1732*5552b385SBrandon       }
1733c1cad2e7SMatthew G. Knepley       // Face Midpoint Vertices on Current Body
1734*5552b385SBrandon       if (islite) {
1735*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1736*5552b385SBrandon       } else {
17379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1738*5552b385SBrandon       }
17399566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
174028b400f6SJacob Faibussowitsch       PetscCheck(BFfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
17419566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
1742c1cad2e7SMatthew G. Knepley 
1743c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1744c1cad2e7SMatthew G. Knepley         ego    face = fobjs[f];
1745c1cad2e7SMatthew G. Knepley         double range[4], avgUV[2], cntrPnt[18];
1746c1cad2e7SMatthew G. Knepley         int    peri, id;
1747c1cad2e7SMatthew G. Knepley 
1748*5552b385SBrandon         if (islite) {
1749*5552b385SBrandon           id = EGlite_indexBodyTopo(body, face);
1750*5552b385SBrandon           PetscCall(EGlite_getRange(face, range, &peri));
1751*5552b385SBrandon         } else {
1752c1cad2e7SMatthew G. Knepley           id = EG_indexBodyTopo(body, face);
17539566063dSJacob Faibussowitsch           PetscCall(EG_getRange(face, range, &peri));
1754*5552b385SBrandon         }
1755c1cad2e7SMatthew G. Knepley 
1756c1cad2e7SMatthew G. Knepley         avgUV[0] = (range[0] + range[1]) / 2.;
1757c1cad2e7SMatthew G. Knepley         avgUV[1] = (range[2] + range[3]) / 2.;
1758*5552b385SBrandon 
1759*5552b385SBrandon         if (islite) {
1760*5552b385SBrandon           PetscCall(EGlite_evaluate(face, avgUV, cntrPnt));
1761*5552b385SBrandon         } else {
17629566063dSJacob Faibussowitsch           PetscCall(EG_evaluate(face, avgUV, cntrPnt));
1763*5552b385SBrandon         }
1764c1cad2e7SMatthew G. Knepley 
1765c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 0] = cntrPnt[0];
1766c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 1] = cntrPnt[1];
1767c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 2] = cntrPnt[2];
1768c1cad2e7SMatthew G. Knepley       }
1769*5552b385SBrandon       if (islite) {
1770*5552b385SBrandon         EGlite_free(fobjs);
1771*5552b385SBrandon       } else {
1772c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1773*5552b385SBrandon       }
1774c1cad2e7SMatthew G. Knepley 
1775c1cad2e7SMatthew G. Knepley       // Define Cells :: Note - This could be incorporated in the Face Midpoint Vertices Loop but was kept separate for clarity
1776*5552b385SBrandon       if (islite) {
1777*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1778*5552b385SBrandon       } else {
17799566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1780*5552b385SBrandon       }
1781c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1782c1cad2e7SMatthew G. Knepley         ego face = fobjs[f];
1783c1cad2e7SMatthew G. Knepley         int fID, midFaceID, midPntID, startID, endID, Nl;
1784c1cad2e7SMatthew G. Knepley 
1785*5552b385SBrandon         if (islite) {
1786*5552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
1787*5552b385SBrandon         } else {
17885f80ce2aSJacob Faibussowitsch           fID = EG_indexBodyTopo(body, face);
1789*5552b385SBrandon         }
1790*5552b385SBrandon 
1791c1cad2e7SMatthew G. Knepley         midFaceID = numVertices + numEdges + bodyFaceIndexStart + fID - 1;
1792c1cad2e7SMatthew G. Knepley         // Must Traverse Loop to ensure we have all necessary information like the sense (+/- 1) of the edges.
1793c1cad2e7SMatthew G. Knepley         // TODO :: Only handles single loop faces (No holes). The choices for handling multiloop faces are:
1794*5552b385SBrandon         //            1) Use the DMPlexCreateGeomFromFile() with the -dm_plex_geom_with_tess = 1 option.
1795c1cad2e7SMatthew G. Knepley         //               This will use a default EGADS tessellation as an initial surface mesh.
1796d5b43468SJose E. Roman         //            2) Create the initial surface mesh via a 2D mesher :: Currently not available (?future?)
1797c1cad2e7SMatthew G. Knepley         //               May I suggest the XXXX as a starting point?
1798c1cad2e7SMatthew G. Knepley 
1799*5552b385SBrandon         if (islite) {
1800*5552b385SBrandon           PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
1801*5552b385SBrandon         } else {
18029566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
1803*5552b385SBrandon         }
1804c1cad2e7SMatthew G. Knepley 
1805*5552b385SBrandon         PetscCheck(Nl == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face has %" PetscInt_FMT " Loops. Can only handle Faces with 1 Loop. Please use --dm_plex_geom_with_tess = 1 Option", Nl);
1806c1cad2e7SMatthew G. Knepley         for (int l = 0; l < Nl; ++l) {
1807c1cad2e7SMatthew G. Knepley           ego loop = lobjs[l];
1808c1cad2e7SMatthew G. Knepley 
1809*5552b385SBrandon           if (islite) {
1810*5552b385SBrandon             PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
1811*5552b385SBrandon           } else {
18129566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
1813*5552b385SBrandon           }
1814*5552b385SBrandon 
1815c1cad2e7SMatthew G. Knepley           for (int e = 0; e < Ne; ++e) {
1816c1cad2e7SMatthew G. Knepley             ego edge = eobjs[e];
1817c1cad2e7SMatthew G. Knepley             int eid, eOffset;
1818c1cad2e7SMatthew G. Knepley 
1819*5552b385SBrandon             if (islite) {
1820*5552b385SBrandon               PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1821*5552b385SBrandon               eid = EGlite_indexBodyTopo(body, edge);
1822*5552b385SBrandon             } else {
18239566063dSJacob Faibussowitsch               PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1824c1cad2e7SMatthew G. Knepley               eid = EG_indexBodyTopo(body, edge);
1825*5552b385SBrandon             }
1826ad540459SPierre Jolivet             if (mtype == DEGENERATE) continue;
1827c1cad2e7SMatthew G. Knepley 
1828c1cad2e7SMatthew G. Knepley             // get relative offset from globalEdgeID Vector
18299566063dSJacob Faibussowitsch             PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
1830*5552b385SBrandon             PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " of Body %" PetscInt_FMT " not found in edgeMap. Global Edge ID :: %" PetscInt_FMT, eid, b, bodyEdgeGlobalIndexStart + eid - 1);
18319566063dSJacob Faibussowitsch             PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1832c1cad2e7SMatthew G. Knepley 
1833c1cad2e7SMatthew G. Knepley             midPntID = numVertices + bodyEdgeIndexStart + eOffset - 1;
1834c1cad2e7SMatthew G. Knepley 
1835*5552b385SBrandon             if (islite) {
1836*5552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1837*5552b385SBrandon             } else {
18389566063dSJacob Faibussowitsch               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
1839*5552b385SBrandon             }
1840c1cad2e7SMatthew G. Knepley 
18419371c9d4SSatish Balay             if (eSenses[e] > 0) {
1842*5552b385SBrandon               if (islite) {
1843*5552b385SBrandon                 startID = EGlite_indexBodyTopo(body, nobjs[0]);
1844*5552b385SBrandon                 endID   = EGlite_indexBodyTopo(body, nobjs[1]);
1845*5552b385SBrandon               } else {
18469371c9d4SSatish Balay                 startID = EG_indexBodyTopo(body, nobjs[0]);
18479371c9d4SSatish Balay                 endID   = EG_indexBodyTopo(body, nobjs[1]);
1848*5552b385SBrandon               }
1849*5552b385SBrandon             } else {
1850*5552b385SBrandon               if (islite) {
1851*5552b385SBrandon                 startID = EGlite_indexBodyTopo(body, nobjs[1]);
1852*5552b385SBrandon                 endID   = EGlite_indexBodyTopo(body, nobjs[0]);
18539371c9d4SSatish Balay               } else {
18549371c9d4SSatish Balay                 startID = EG_indexBodyTopo(body, nobjs[1]);
18559371c9d4SSatish Balay                 endID   = EG_indexBodyTopo(body, nobjs[0]);
18569371c9d4SSatish Balay               }
1857*5552b385SBrandon             }
1858c1cad2e7SMatthew G. Knepley 
1859c1cad2e7SMatthew G. Knepley             // Define 2 Cells per Edge with correct orientation
1860c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 0] = midFaceID;
1861c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 1] = bodyVertexIndexStart + startID - 1;
1862c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 2] = midPntID;
1863c1cad2e7SMatthew G. Knepley 
1864c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 3] = midFaceID;
1865c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 4] = midPntID;
1866c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 5] = bodyVertexIndexStart + endID - 1;
1867c1cad2e7SMatthew G. Knepley 
1868c1cad2e7SMatthew G. Knepley             cellCntr = cellCntr + 2;
1869c1cad2e7SMatthew G. Knepley           }
1870c1cad2e7SMatthew G. Knepley         }
1871c1cad2e7SMatthew G. Knepley       }
1872*5552b385SBrandon       if (islite) {
1873*5552b385SBrandon         EGlite_free(fobjs);
1874*5552b385SBrandon       } else {
1875c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1876c1cad2e7SMatthew G. Knepley       }
1877c1cad2e7SMatthew G. Knepley     }
1878*5552b385SBrandon   }
1879c1cad2e7SMatthew G. Knepley 
1880c1cad2e7SMatthew G. Knepley   // Generate DMPlex
18819566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
18829566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coords, cells));
188363a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %" PetscInt_FMT " \n", numCells));
188463a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, " Total Number of Unique Vertices = %" PetscInt_FMT " \n", numVertices));
1885c1cad2e7SMatthew G. Knepley 
1886c1cad2e7SMatthew G. Knepley   // Embed EGADS model in DM
1887c1cad2e7SMatthew G. Knepley   {
1888c1cad2e7SMatthew G. Knepley     PetscContainer modelObj, contextObj;
1889c1cad2e7SMatthew G. Knepley 
18909566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
18919566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
1892*5552b385SBrandon     if (islite) {
1893*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSliteDestroy_Private));
1894*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Model", (PetscObject)modelObj));
1895*5552b385SBrandon     } else {
1896*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSDestroy_Private));
18979566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
1898*5552b385SBrandon     }
18999566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
1900c1cad2e7SMatthew G. Knepley 
19019566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
19029566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
1903*5552b385SBrandon 
1904*5552b385SBrandon     if (islite) {
1905*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSliteClose_Private));
1906*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Context", (PetscObject)contextObj));
1907*5552b385SBrandon     } else {
1908*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSClose_Private));
19099566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
1910*5552b385SBrandon     }
19119566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
1912c1cad2e7SMatthew G. Knepley   }
1913c1cad2e7SMatthew G. Knepley   // Label points
1914c1cad2e7SMatthew G. Knepley   PetscInt nStart, nEnd;
1915c1cad2e7SMatthew G. Knepley 
19169566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
19179566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
19189566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
19199566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
19209566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
19219566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
19229566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
19239566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
1924c1cad2e7SMatthew G. Knepley 
19259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
1926c1cad2e7SMatthew G. Knepley 
1927c1cad2e7SMatthew G. Knepley   cellCntr = 0;
1928c1cad2e7SMatthew G. Knepley   for (b = 0; b < nbodies; ++b) {
1929c1cad2e7SMatthew G. Knepley     ego           body = bodies[b];
1930c1cad2e7SMatthew G. Knepley     int           Nv, Ne, Nf;
1931c1cad2e7SMatthew G. Knepley     PetscInt      bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
1932c1cad2e7SMatthew G. Knepley     PetscHashIter BViter, BEiter, BEGiter, BFiter, EMiter;
1933c1cad2e7SMatthew G. Knepley     PetscBool     BVfound, BEfound, BEGfound, BFfound, EMfound;
1934c1cad2e7SMatthew G. Knepley 
19359566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
193628b400f6SJacob Faibussowitsch     PetscCheck(BVfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyVertexMap", b);
19379566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
1938c1cad2e7SMatthew G. Knepley 
19399566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
194028b400f6SJacob Faibussowitsch     PetscCheck(BEfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeMap", b);
19419566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
1942c1cad2e7SMatthew G. Knepley 
19439566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
194428b400f6SJacob Faibussowitsch     PetscCheck(BFfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
19459566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
1946c1cad2e7SMatthew G. Knepley 
19479566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
194828b400f6SJacob Faibussowitsch     PetscCheck(BEGfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeGlobalMap", b);
19499566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
1950c1cad2e7SMatthew G. Knepley 
1951*5552b385SBrandon     if (islite) {
1952*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1953*5552b385SBrandon     } else {
19549566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
1955*5552b385SBrandon     }
1956*5552b385SBrandon 
1957c1cad2e7SMatthew G. Knepley     for (int f = 0; f < Nf; ++f) {
1958c1cad2e7SMatthew G. Knepley       ego face = fobjs[f];
1959c1cad2e7SMatthew G. Knepley       int fID, Nl;
1960c1cad2e7SMatthew G. Knepley 
1961*5552b385SBrandon       if (islite) {
1962*5552b385SBrandon         fID = EGlite_indexBodyTopo(body, face);
1963*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
1964*5552b385SBrandon       } else {
19655f80ce2aSJacob Faibussowitsch         fID = EG_indexBodyTopo(body, face);
19669566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
1967*5552b385SBrandon       }
1968*5552b385SBrandon 
1969c1cad2e7SMatthew G. Knepley       for (int l = 0; l < Nl; ++l) {
1970c1cad2e7SMatthew G. Knepley         ego loop = lobjs[l];
1971c1cad2e7SMatthew G. Knepley         int lid;
1972c1cad2e7SMatthew G. Knepley 
1973*5552b385SBrandon         if (islite) {
1974*5552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
1975*5552b385SBrandon         } else {
19765f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
1977*5552b385SBrandon         }
1978c1cad2e7SMatthew G. Knepley 
1979*5552b385SBrandon         PetscCheck(Nl == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %" PetscInt_FMT " has %" PetscInt_FMT " > 1 faces, which is not supported", lid, Nf);
1980*5552b385SBrandon 
1981*5552b385SBrandon         if (islite) {
1982*5552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
1983*5552b385SBrandon         } else {
19849566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
1985*5552b385SBrandon         }
1986*5552b385SBrandon 
1987c1cad2e7SMatthew G. Knepley         for (int e = 0; e < Ne; ++e) {
1988c1cad2e7SMatthew G. Knepley           ego edge = eobjs[e];
1989c1cad2e7SMatthew G. Knepley           int eid, eOffset;
1990c1cad2e7SMatthew G. Knepley 
1991c1cad2e7SMatthew G. Knepley           // Skip DEGENERATE Edges
1992*5552b385SBrandon           if (islite) {
1993*5552b385SBrandon             PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1994*5552b385SBrandon           } else {
19959566063dSJacob Faibussowitsch             PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1996*5552b385SBrandon           }
1997*5552b385SBrandon 
1998*5552b385SBrandon           if (mtype == DEGENERATE) { continue; }
1999*5552b385SBrandon 
2000*5552b385SBrandon           if (islite) {
2001*5552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
2002*5552b385SBrandon           } else {
20035f80ce2aSJacob Faibussowitsch             eid = EG_indexBodyTopo(body, edge);
2004*5552b385SBrandon           }
2005c1cad2e7SMatthew G. Knepley 
2006c1cad2e7SMatthew G. Knepley           // get relative offset from globalEdgeID Vector
20079566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
2008*5552b385SBrandon           PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " of Body %" PetscInt_FMT " not found in edgeMap. Global Edge ID :: %" PetscInt_FMT, eid, b, bodyEdgeGlobalIndexStart + eid - 1);
20099566063dSJacob Faibussowitsch           PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
2010c1cad2e7SMatthew G. Knepley 
2011*5552b385SBrandon           if (islite) {
2012*5552b385SBrandon             PetscCall(EGlite_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
2013*5552b385SBrandon           } else {
20149566063dSJacob Faibussowitsch             PetscCall(EG_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
2015*5552b385SBrandon           }
2016*5552b385SBrandon 
2017c1cad2e7SMatthew G. Knepley           for (int v = 0; v < Nv; ++v) {
2018c1cad2e7SMatthew G. Knepley             ego vertex = nobjs[v];
2019c1cad2e7SMatthew G. Knepley             int vID;
2020c1cad2e7SMatthew G. Knepley 
2021*5552b385SBrandon             if (islite) {
2022*5552b385SBrandon               vID = EGlite_indexBodyTopo(body, vertex);
2023*5552b385SBrandon             } else {
20245f80ce2aSJacob Faibussowitsch               vID = EG_indexBodyTopo(body, vertex);
2025*5552b385SBrandon             }
2026*5552b385SBrandon 
20279566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, nStart + bodyVertexIndexStart + vID - 1, b));
20289566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(vertexLabel, nStart + bodyVertexIndexStart + vID - 1, vID));
2029c1cad2e7SMatthew G. Knepley           }
2030*5552b385SBrandon           if (islite) {
2031*5552b385SBrandon             EGlite_free(nobjs);
2032*5552b385SBrandon           } else {
2033c1cad2e7SMatthew G. Knepley             EG_free(nobjs);
2034*5552b385SBrandon           }
2035c1cad2e7SMatthew G. Knepley 
20369566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, b));
20379566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(edgeLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, eid));
2038c1cad2e7SMatthew G. Knepley 
2039c1cad2e7SMatthew G. Knepley           // Define Cell faces
2040c1cad2e7SMatthew G. Knepley           for (int jj = 0; jj < 2; ++jj) {
20419566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cellCntr, b));
20429566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cellCntr, fID));
20439566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cellCntr, &cone));
2044c1cad2e7SMatthew G. Knepley 
20459566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[0], b));
20469566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cone[0], fID));
2047c1cad2e7SMatthew G. Knepley 
20489566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[1], b));
20499566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(edgeLabel, cone[1], eid));
2050c1cad2e7SMatthew G. Knepley 
20519566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[2], b));
20529566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cone[2], fID));
2053c1cad2e7SMatthew G. Knepley 
2054c1cad2e7SMatthew G. Knepley             cellCntr = cellCntr + 1;
2055c1cad2e7SMatthew G. Knepley           }
2056c1cad2e7SMatthew G. Knepley         }
2057c1cad2e7SMatthew G. Knepley       }
2058*5552b385SBrandon       if (islite) {
2059*5552b385SBrandon         EGlite_free(lobjs);
2060*5552b385SBrandon       } else {
2061c1cad2e7SMatthew G. Knepley         EG_free(lobjs);
2062*5552b385SBrandon       }
2063c1cad2e7SMatthew G. Knepley 
20649566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, b));
20659566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(faceLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, fID));
2066c1cad2e7SMatthew G. Knepley     }
2067*5552b385SBrandon     if (islite) {
2068*5552b385SBrandon       EGlite_free(fobjs);
2069*5552b385SBrandon     } else {
2070c1cad2e7SMatthew G. Knepley       EG_free(fobjs);
2071c1cad2e7SMatthew G. Knepley     }
2072*5552b385SBrandon   }
2073c1cad2e7SMatthew G. Knepley 
20749566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&edgeMap));
20759566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyIndexMap));
20769566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyVertexMap));
20779566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyEdgeMap));
20789566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyEdgeGlobalMap));
20799566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyFaceMap));
2080c1cad2e7SMatthew G. Knepley 
2081c1cad2e7SMatthew G. Knepley   *newdm = dm;
20823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2083c1cad2e7SMatthew G. Knepley }
2084c1cad2e7SMatthew G. Knepley 
2085*5552b385SBrandon PetscErrorCode DMPlexCreateGeom_Tess_Internal(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
2086d71ae5a4SJacob Faibussowitsch {
2087*5552b385SBrandon   /* EGADSlite variables */
2088c1cad2e7SMatthew G. Knepley   ego    geom, *bodies, *fobjs;
2089c1cad2e7SMatthew G. Knepley   int    b, oclass, mtype, nbodies, *senses;
2090c1cad2e7SMatthew G. Knepley   int    totalNumTris = 0, totalNumPoints = 0;
2091c1cad2e7SMatthew G. Knepley   double boundBox[6] = {0., 0., 0., 0., 0., 0.}, tessSize;
2092c1cad2e7SMatthew G. Knepley   /* PETSc variables */
2093c1cad2e7SMatthew G. Knepley   DM              dm;
2094*5552b385SBrandon   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
2095c1cad2e7SMatthew G. Knepley   PetscHMapI      pointIndexStartMap = NULL, triIndexStartMap = NULL, pTypeLabelMap = NULL, pIndexLabelMap = NULL;
2096c1cad2e7SMatthew G. Knepley   PetscHMapI      pBodyIndexLabelMap = NULL, triFaceIDLabelMap = NULL, triBodyIDLabelMap = NULL;
2097c1cad2e7SMatthew G. Knepley   PetscInt        dim = -1, cdim = -1, numCorners = 0, counter = 0;
2098c1cad2e7SMatthew G. Knepley   PetscInt       *cells  = NULL;
2099c1cad2e7SMatthew G. Knepley   const PetscInt *cone   = NULL;
2100c1cad2e7SMatthew G. Knepley   PetscReal      *coords = NULL;
2101c1cad2e7SMatthew G. Knepley   PetscMPIInt     rank;
2102c1cad2e7SMatthew G. Knepley 
2103c1cad2e7SMatthew G. Knepley   PetscFunctionBeginUser;
21049566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2105c5853193SPierre Jolivet   if (rank == 0) {
2106c1cad2e7SMatthew G. Knepley     // ---------------------------------------------------------------------------------------------------
2107c1cad2e7SMatthew G. Knepley     // Generate Petsc Plex from EGADSlite created Tessellation of geometry
2108c1cad2e7SMatthew G. Knepley     // ---------------------------------------------------------------------------------------------------
2109c1cad2e7SMatthew G. Knepley 
2110d5b43468SJose E. Roman     // Calculate cell and vertex sizes
2111*5552b385SBrandon     if (islite) {
2112*5552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
2113*5552b385SBrandon     } else {
21149566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
2115*5552b385SBrandon     }
2116c1cad2e7SMatthew G. Knepley 
21179566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pointIndexStartMap));
21189566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triIndexStartMap));
21199566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pTypeLabelMap));
21209566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pIndexLabelMap));
21219566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pBodyIndexLabelMap));
21229566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triFaceIDLabelMap));
21239566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triBodyIDLabelMap));
2124c1cad2e7SMatthew G. Knepley 
2125c1cad2e7SMatthew G. Knepley     /* Create Tessellation of Bodies */
2126*5552b385SBrandon     ego *tessArray;
2127c1cad2e7SMatthew G. Knepley 
2128*5552b385SBrandon     PetscCall(PetscMalloc1(nbodies, &tessArray));
2129c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
2130c1cad2e7SMatthew G. Knepley       ego           body      = bodies[b];
2131c1cad2e7SMatthew G. Knepley       double        params[3] = {0.0, 0.0, 0.0}; // Parameters for Tessellation
2132c1cad2e7SMatthew G. Knepley       int           Nf, bodyNumPoints = 0, bodyNumTris = 0;
2133c1cad2e7SMatthew G. Knepley       PetscHashIter PISiter, TISiter;
2134c1cad2e7SMatthew G. Knepley       PetscBool     PISfound, TISfound;
2135c1cad2e7SMatthew G. Knepley 
2136c1cad2e7SMatthew G. Knepley       /* Store Start Index for each Body's Point and Tris */
21379566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
21389566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(triIndexStartMap, b, &TISiter, &TISfound));
2139c1cad2e7SMatthew G. Knepley 
21409566063dSJacob Faibussowitsch       if (!PISfound) PetscCall(PetscHMapISet(pointIndexStartMap, b, totalNumPoints));
21419566063dSJacob Faibussowitsch       if (!TISfound) PetscCall(PetscHMapISet(triIndexStartMap, b, totalNumTris));
2142c1cad2e7SMatthew G. Knepley 
2143c1cad2e7SMatthew G. Knepley       /* Calculate Tessellation parameters based on Bounding Box */
2144c1cad2e7SMatthew G. Knepley       /* Get Bounding Box Dimensions of the BODY */
2145*5552b385SBrandon       if (islite) {
2146*5552b385SBrandon         PetscCall(EGlite_getBoundingBox(body, boundBox));
2147*5552b385SBrandon       } else {
21489566063dSJacob Faibussowitsch         PetscCall(EG_getBoundingBox(body, boundBox));
2149*5552b385SBrandon       }
2150*5552b385SBrandon 
2151c1cad2e7SMatthew G. Knepley       tessSize = boundBox[3] - boundBox[0];
2152c1cad2e7SMatthew G. Knepley       if (tessSize < boundBox[4] - boundBox[1]) tessSize = boundBox[4] - boundBox[1];
2153c1cad2e7SMatthew G. Knepley       if (tessSize < boundBox[5] - boundBox[2]) tessSize = boundBox[5] - boundBox[2];
2154c1cad2e7SMatthew G. Knepley 
2155c1cad2e7SMatthew G. Knepley       // TODO :: May want to give users tessellation parameter options //
2156c1cad2e7SMatthew G. Knepley       params[0] = 0.0250 * tessSize;
2157c1cad2e7SMatthew G. Knepley       params[1] = 0.0075 * tessSize;
2158c1cad2e7SMatthew G. Knepley       params[2] = 15.0;
2159c1cad2e7SMatthew G. Knepley 
2160*5552b385SBrandon       if (islite) {
2161*5552b385SBrandon         PetscCall(EGlite_makeTessBody(body, params, &tessArray[b]));
2162*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
2163*5552b385SBrandon       } else {
21649566063dSJacob Faibussowitsch         PetscCall(EG_makeTessBody(body, params, &tessArray[b]));
21659566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
2166*5552b385SBrandon       }
2167c1cad2e7SMatthew G. Knepley 
2168c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
2169c1cad2e7SMatthew G. Knepley         ego           face = fobjs[f];
2170c1cad2e7SMatthew G. Knepley         int           len, fID, ntris;
2171c1cad2e7SMatthew G. Knepley         const int    *ptype, *pindex, *ptris, *ptric;
2172c1cad2e7SMatthew G. Knepley         const double *pxyz, *puv;
2173c1cad2e7SMatthew G. Knepley 
2174c1cad2e7SMatthew G. Knepley         // Get Face ID //
2175*5552b385SBrandon         if (islite) {
2176*5552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
2177*5552b385SBrandon         } else {
2178c1cad2e7SMatthew G. Knepley           fID = EG_indexBodyTopo(body, face);
2179*5552b385SBrandon         }
2180c1cad2e7SMatthew G. Knepley 
2181c1cad2e7SMatthew G. Knepley         // Checkout the Surface Tessellation //
2182*5552b385SBrandon         if (islite) {
2183*5552b385SBrandon           PetscCall(EGlite_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
2184*5552b385SBrandon         } else {
21859566063dSJacob Faibussowitsch           PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
2186*5552b385SBrandon         }
2187c1cad2e7SMatthew G. Knepley 
2188c1cad2e7SMatthew G. Knepley         // Determine total number of triangle cells in the tessellation //
2189c1cad2e7SMatthew G. Knepley         bodyNumTris += (int)ntris;
2190c1cad2e7SMatthew G. Knepley 
2191c1cad2e7SMatthew G. Knepley         // Check out the point index and coordinate //
2192c1cad2e7SMatthew G. Knepley         for (int p = 0; p < len; ++p) {
2193c1cad2e7SMatthew G. Knepley           int global;
2194c1cad2e7SMatthew G. Knepley 
2195*5552b385SBrandon           if (islite) {
2196*5552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, p + 1, &global));
2197*5552b385SBrandon           } else {
21989566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, p + 1, &global));
2199*5552b385SBrandon           }
2200c1cad2e7SMatthew G. Knepley 
2201c1cad2e7SMatthew G. Knepley           // Determine the total number of points in the tessellation //
2202c1cad2e7SMatthew G. Knepley           bodyNumPoints = PetscMax(bodyNumPoints, global);
2203c1cad2e7SMatthew G. Knepley         }
2204c1cad2e7SMatthew G. Knepley       }
2205*5552b385SBrandon       if (islite) {
2206*5552b385SBrandon         EGlite_free(fobjs);
2207*5552b385SBrandon       } else {
2208c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
2209*5552b385SBrandon       }
2210c1cad2e7SMatthew G. Knepley 
2211c1cad2e7SMatthew G. Knepley       totalNumPoints += bodyNumPoints;
2212c1cad2e7SMatthew G. Knepley       totalNumTris += bodyNumTris;
2213c1cad2e7SMatthew G. Knepley     }
2214c1cad2e7SMatthew G. Knepley 
2215c1cad2e7SMatthew G. Knepley     dim        = 2;
2216c1cad2e7SMatthew G. Knepley     cdim       = 3;
2217c1cad2e7SMatthew G. Knepley     numCorners = 3;
2218c1cad2e7SMatthew G. Knepley 
2219c1cad2e7SMatthew G. Knepley     /* NEED TO DEFINE MATRICES/VECTORS TO STORE GEOM REFERENCE DATA   */
2220c1cad2e7SMatthew G. Knepley     /* Fill in below and use to define DMLabels after DMPlex creation */
22219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(totalNumPoints * cdim, &coords, totalNumTris * numCorners, &cells));
2222c1cad2e7SMatthew G. Knepley 
2223c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
2224c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
2225c1cad2e7SMatthew G. Knepley       int           Nf;
2226c1cad2e7SMatthew G. Knepley       PetscInt      pointIndexStart;
2227c1cad2e7SMatthew G. Knepley       PetscHashIter PISiter;
2228c1cad2e7SMatthew G. Knepley       PetscBool     PISfound;
2229c1cad2e7SMatthew G. Knepley 
22309566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
2231*5552b385SBrandon       PetscCheck(PISfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in pointIndexStartMap", b);
22329566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(pointIndexStartMap, b, &pointIndexStart));
2233c1cad2e7SMatthew G. Knepley 
2234*5552b385SBrandon       if (islite) {
2235*5552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
2236*5552b385SBrandon       } else {
22379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
2238*5552b385SBrandon       }
2239c1cad2e7SMatthew G. Knepley 
2240c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
2241c1cad2e7SMatthew G. Knepley         /* Get Face Object */
2242c1cad2e7SMatthew G. Knepley         ego           face = fobjs[f];
2243c1cad2e7SMatthew G. Knepley         int           len, fID, ntris;
2244c1cad2e7SMatthew G. Knepley         const int    *ptype, *pindex, *ptris, *ptric;
2245c1cad2e7SMatthew G. Knepley         const double *pxyz, *puv;
2246c1cad2e7SMatthew G. Knepley 
2247c1cad2e7SMatthew G. Knepley         /* Get Face ID */
2248*5552b385SBrandon         if (islite) {
2249*5552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
2250*5552b385SBrandon         } else {
2251c1cad2e7SMatthew G. Knepley           fID = EG_indexBodyTopo(body, face);
2252*5552b385SBrandon         }
2253c1cad2e7SMatthew G. Knepley 
2254c1cad2e7SMatthew G. Knepley         /* Checkout the Surface Tessellation */
2255*5552b385SBrandon         if (islite) {
2256*5552b385SBrandon           PetscCall(EGlite_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
2257*5552b385SBrandon         } else {
22589566063dSJacob Faibussowitsch           PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
2259*5552b385SBrandon         }
2260c1cad2e7SMatthew G. Knepley 
2261c1cad2e7SMatthew G. Knepley         /* Check out the point index and coordinate */
2262c1cad2e7SMatthew G. Knepley         for (int p = 0; p < len; ++p) {
2263c1cad2e7SMatthew G. Knepley           int           global;
2264c1cad2e7SMatthew G. Knepley           PetscHashIter PTLiter, PILiter, PBLiter;
2265c1cad2e7SMatthew G. Knepley           PetscBool     PTLfound, PILfound, PBLfound;
2266c1cad2e7SMatthew G. Knepley 
2267*5552b385SBrandon           if (islite) {
2268*5552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, p + 1, &global));
2269*5552b385SBrandon           } else {
22709566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, p + 1, &global));
2271*5552b385SBrandon           }
2272c1cad2e7SMatthew G. Knepley 
2273c1cad2e7SMatthew G. Knepley           /* Set the coordinates array for DAG */
2274c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 0] = pxyz[(p * 3) + 0];
2275c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 1] = pxyz[(p * 3) + 1];
2276c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 2] = pxyz[(p * 3) + 2];
2277c1cad2e7SMatthew G. Knepley 
2278c1cad2e7SMatthew G. Knepley           /* Store Geometry Label Information for DMLabel assignment later */
22799566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pTypeLabelMap, global - 1 + pointIndexStart, &PTLiter, &PTLfound));
22809566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pIndexLabelMap, global - 1 + pointIndexStart, &PILiter, &PILfound));
22819566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pBodyIndexLabelMap, global - 1 + pointIndexStart, &PBLiter, &PBLfound));
2282c1cad2e7SMatthew G. Knepley 
22839566063dSJacob Faibussowitsch           if (!PTLfound) PetscCall(PetscHMapISet(pTypeLabelMap, global - 1 + pointIndexStart, ptype[p]));
22849566063dSJacob Faibussowitsch           if (!PILfound) PetscCall(PetscHMapISet(pIndexLabelMap, global - 1 + pointIndexStart, pindex[p]));
22859566063dSJacob Faibussowitsch           if (!PBLfound) PetscCall(PetscHMapISet(pBodyIndexLabelMap, global - 1 + pointIndexStart, b));
2286c1cad2e7SMatthew G. Knepley 
22879566063dSJacob Faibussowitsch           if (ptype[p] < 0) PetscCall(PetscHMapISet(pIndexLabelMap, global - 1 + pointIndexStart, fID));
2288c1cad2e7SMatthew G. Knepley         }
2289c1cad2e7SMatthew G. Knepley 
2290c1cad2e7SMatthew G. Knepley         for (int t = 0; t < (int)ntris; ++t) {
2291c1cad2e7SMatthew G. Knepley           int           global, globalA, globalB;
2292c1cad2e7SMatthew G. Knepley           PetscHashIter TFLiter, TBLiter;
2293c1cad2e7SMatthew G. Knepley           PetscBool     TFLfound, TBLfound;
2294c1cad2e7SMatthew G. Knepley 
2295*5552b385SBrandon           if (islite) {
2296*5552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 0], &global));
2297*5552b385SBrandon           } else {
22989566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 0], &global));
2299*5552b385SBrandon           }
2300c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 0] = global - 1 + pointIndexStart;
2301c1cad2e7SMatthew G. Knepley 
2302*5552b385SBrandon           if (islite) {
2303*5552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 1], &globalA));
2304*5552b385SBrandon           } else {
23059566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 1], &globalA));
2306*5552b385SBrandon           }
2307c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 1] = globalA - 1 + pointIndexStart;
2308c1cad2e7SMatthew G. Knepley 
2309*5552b385SBrandon           if (islite) {
2310*5552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 2], &globalB));
2311*5552b385SBrandon           } else {
23129566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 2], &globalB));
2313*5552b385SBrandon           }
2314c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 2] = globalB - 1 + pointIndexStart;
2315c1cad2e7SMatthew G. Knepley 
23169566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(triFaceIDLabelMap, counter, &TFLiter, &TFLfound));
23179566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(triBodyIDLabelMap, counter, &TBLiter, &TBLfound));
2318c1cad2e7SMatthew G. Knepley 
23199566063dSJacob Faibussowitsch           if (!TFLfound) PetscCall(PetscHMapISet(triFaceIDLabelMap, counter, fID));
23209566063dSJacob Faibussowitsch           if (!TBLfound) PetscCall(PetscHMapISet(triBodyIDLabelMap, counter, b));
2321c1cad2e7SMatthew G. Knepley 
2322c1cad2e7SMatthew G. Knepley           counter += 1;
2323c1cad2e7SMatthew G. Knepley         }
2324c1cad2e7SMatthew G. Knepley       }
2325*5552b385SBrandon       if (islite) {
2326*5552b385SBrandon         EGlite_free(fobjs);
2327*5552b385SBrandon       } else {
2328c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
2329c1cad2e7SMatthew G. Knepley       }
2330c1cad2e7SMatthew G. Knepley     }
2331*5552b385SBrandon     PetscCall(PetscFree(tessArray));
2332*5552b385SBrandon   }
2333c1cad2e7SMatthew G. Knepley 
2334c1cad2e7SMatthew G. Knepley   //Build DMPlex
23359566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, totalNumTris, totalNumPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
23369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coords, cells));
2337c1cad2e7SMatthew G. Knepley 
2338c1cad2e7SMatthew G. Knepley   // Embed EGADS model in DM
2339c1cad2e7SMatthew G. Knepley   {
2340c1cad2e7SMatthew G. Knepley     PetscContainer modelObj, contextObj;
2341c1cad2e7SMatthew G. Knepley 
23429566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
23439566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
2344*5552b385SBrandon     if (islite) {
2345*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, (PetscCtxDestroyFn *)DMPlexEGADSliteDestroy_Private));
2346*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Model", (PetscObject)modelObj));
2347*5552b385SBrandon     } else {
2348*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, (PetscCtxDestroyFn *)DMPlexEGADSDestroy_Private));
23499566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
2350*5552b385SBrandon     }
23519566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
2352c1cad2e7SMatthew G. Knepley 
23539566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
23549566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
2355*5552b385SBrandon 
2356*5552b385SBrandon     if (islite) {
2357*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, (PetscCtxDestroyFn *)DMPlexEGADSliteClose_Private));
2358*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Context", (PetscObject)contextObj));
2359*5552b385SBrandon     } else {
2360*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, (PetscCtxDestroyFn *)DMPlexEGADSClose_Private));
23619566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
2362*5552b385SBrandon     }
23639566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
2364c1cad2e7SMatthew G. Knepley   }
2365c1cad2e7SMatthew G. Knepley 
2366c1cad2e7SMatthew G. Knepley   // Label Points
23679566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
23689566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
23699566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
23709566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
23719566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
23729566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
23739566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
23749566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
2375c1cad2e7SMatthew G. Knepley 
2376c1cad2e7SMatthew G. Knepley   /* Get Number of DAG Nodes at each level */
2377c1cad2e7SMatthew G. Knepley   int fStart, fEnd, eStart, eEnd, nStart, nEnd;
2378c1cad2e7SMatthew G. Knepley 
23799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &fStart, &fEnd));
23809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &eStart, &eEnd));
23819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
2382c1cad2e7SMatthew G. Knepley 
2383c1cad2e7SMatthew G. Knepley   /* Set DMLabels for NODES */
2384c1cad2e7SMatthew G. Knepley   for (int n = nStart; n < nEnd; ++n) {
2385c1cad2e7SMatthew G. Knepley     int           pTypeVal, pIndexVal, pBodyVal;
2386c1cad2e7SMatthew G. Knepley     PetscHashIter PTLiter, PILiter, PBLiter;
2387c1cad2e7SMatthew G. Knepley     PetscBool     PTLfound, PILfound, PBLfound;
2388c1cad2e7SMatthew G. Knepley 
2389c1cad2e7SMatthew G. Knepley     //Converted to Hash Tables
23909566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pTypeLabelMap, n - nStart, &PTLiter, &PTLfound));
2391*5552b385SBrandon     PetscCheck(PTLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pTypeLabelMap", n);
23929566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pTypeLabelMap, n - nStart, &pTypeVal));
2393c1cad2e7SMatthew G. Knepley 
23949566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pIndexLabelMap, n - nStart, &PILiter, &PILfound));
2395*5552b385SBrandon     PetscCheck(PILfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pIndexLabelMap", n);
23969566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pIndexLabelMap, n - nStart, &pIndexVal));
2397c1cad2e7SMatthew G. Knepley 
23989566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pBodyIndexLabelMap, n - nStart, &PBLiter, &PBLfound));
2399*5552b385SBrandon     PetscCheck(PBLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pBodyLabelMap", n);
24009566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pBodyIndexLabelMap, n - nStart, &pBodyVal));
2401c1cad2e7SMatthew G. Knepley 
24029566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, n, pBodyVal));
24039566063dSJacob Faibussowitsch     if (pTypeVal == 0) PetscCall(DMLabelSetValue(vertexLabel, n, pIndexVal));
24049566063dSJacob Faibussowitsch     if (pTypeVal > 0) PetscCall(DMLabelSetValue(edgeLabel, n, pIndexVal));
24059566063dSJacob Faibussowitsch     if (pTypeVal < 0) PetscCall(DMLabelSetValue(faceLabel, n, pIndexVal));
2406c1cad2e7SMatthew G. Knepley   }
2407c1cad2e7SMatthew G. Knepley 
2408c1cad2e7SMatthew G. Knepley   /* Set DMLabels for Edges - Based on the DMLabels of the EDGE's NODES */
2409c1cad2e7SMatthew G. Knepley   for (int e = eStart; e < eEnd; ++e) {
2410c1cad2e7SMatthew G. Knepley     int bodyID_0, vertexID_0, vertexID_1, edgeID_0, edgeID_1, faceID_0, faceID_1;
2411c1cad2e7SMatthew G. Knepley 
24129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, e, &cone));
24139566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, cone[0], &bodyID_0)); // Do I need to check the other end?
24149566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, cone[0], &vertexID_0));
24159566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, cone[1], &vertexID_1));
24169566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, cone[0], &edgeID_0));
24179566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, cone[1], &edgeID_1));
24189566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, cone[0], &faceID_0));
24199566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, cone[1], &faceID_1));
2420c1cad2e7SMatthew G. Knepley 
24219566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, e, bodyID_0));
2422c1cad2e7SMatthew G. Knepley 
24239566063dSJacob Faibussowitsch     if (edgeID_0 == edgeID_1) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
24249566063dSJacob Faibussowitsch     else if (vertexID_0 > 0 && edgeID_1 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_1));
24259566063dSJacob Faibussowitsch     else if (vertexID_1 > 0 && edgeID_0 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
2426c1cad2e7SMatthew G. Knepley     else { /* Do Nothing */ }
2427c1cad2e7SMatthew G. Knepley   }
2428c1cad2e7SMatthew G. Knepley 
2429c1cad2e7SMatthew G. Knepley   /* Set DMLabels for Cells */
2430c1cad2e7SMatthew G. Knepley   for (int f = fStart; f < fEnd; ++f) {
2431c1cad2e7SMatthew G. Knepley     int           edgeID_0;
2432c1cad2e7SMatthew G. Knepley     PetscInt      triBodyVal, triFaceVal;
2433c1cad2e7SMatthew G. Knepley     PetscHashIter TFLiter, TBLiter;
2434c1cad2e7SMatthew G. Knepley     PetscBool     TFLfound, TBLfound;
2435c1cad2e7SMatthew G. Knepley 
2436c1cad2e7SMatthew G. Knepley     // Convert to Hash Table
24379566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(triFaceIDLabelMap, f - fStart, &TFLiter, &TFLfound));
2438*5552b385SBrandon     PetscCheck(TFLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in triFaceIDLabelMap", f);
24399566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(triFaceIDLabelMap, f - fStart, &triFaceVal));
2440c1cad2e7SMatthew G. Knepley 
24419566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(triBodyIDLabelMap, f - fStart, &TBLiter, &TBLfound));
2442*5552b385SBrandon     PetscCheck(TBLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in triBodyIDLabelMap", f);
24439566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(triBodyIDLabelMap, f - fStart, &triBodyVal));
2444c1cad2e7SMatthew G. Knepley 
24459566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, f, triBodyVal));
24469566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(faceLabel, f, triFaceVal));
2447c1cad2e7SMatthew G. Knepley 
2448c1cad2e7SMatthew G. Knepley     /* Finish Labeling previously unlabeled DMPlex Edges - Assumes Triangular Cell (3 Edges Max) */
24499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, f, &cone));
2450c1cad2e7SMatthew G. Knepley 
2451c1cad2e7SMatthew G. Knepley     for (int jj = 0; jj < 3; ++jj) {
24529566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(edgeLabel, cone[jj], &edgeID_0));
2453c1cad2e7SMatthew G. Knepley 
2454c1cad2e7SMatthew G. Knepley       if (edgeID_0 < 0) {
24559566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(bodyLabel, cone[jj], triBodyVal));
24569566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(faceLabel, cone[jj], triFaceVal));
2457c1cad2e7SMatthew G. Knepley       }
2458c1cad2e7SMatthew G. Knepley     }
2459c1cad2e7SMatthew G. Knepley   }
2460c1cad2e7SMatthew G. Knepley 
2461c1cad2e7SMatthew G. Knepley   *newdm = dm;
24623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2463c1cad2e7SMatthew G. Knepley }
24647bee2925SMatthew Knepley #endif
24657bee2925SMatthew Knepley 
2466*5552b385SBrandon /*@C
2467*5552b385SBrandon   DMPlexInflateToGeomModelUseXYZ - Snaps the vertex coordinates of a `DMPLEX` object representing the mesh to its geometry if some vertices depart from the model. This usually happens with non-conforming refinement.
2468c1cad2e7SMatthew G. Knepley 
246920f4b53cSBarry Smith   Collective
2470c1cad2e7SMatthew G. Knepley 
2471c1cad2e7SMatthew G. Knepley   Input Parameter:
2472a1cb98faSBarry Smith . dm - The uninflated `DM` object representing the mesh
2473c1cad2e7SMatthew G. Knepley 
2474c1cad2e7SMatthew G. Knepley   Level: intermediate
2475c1cad2e7SMatthew G. Knepley 
24761cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`
2477c1cad2e7SMatthew G. Knepley @*/
2478*5552b385SBrandon PetscErrorCode DMPlexInflateToGeomModelUseXYZ(DM dm)
2479d71ae5a4SJacob Faibussowitsch {
2480c1cad2e7SMatthew G. Knepley #if defined(PETSC_HAVE_EGADS)
2481c1cad2e7SMatthew G. Knepley   /* EGADS Variables */
2482*5552b385SBrandon   ego    model, geom, body, face, edge, vertex;
2483c1cad2e7SMatthew G. Knepley   ego   *bodies;
2484c1cad2e7SMatthew G. Knepley   int    Nb, oclass, mtype, *senses;
2485*5552b385SBrandon   double result[4];
2486c1cad2e7SMatthew G. Knepley   /* PETSc Variables */
2487c1cad2e7SMatthew G. Knepley   DM             cdm;
2488c1cad2e7SMatthew G. Knepley   PetscContainer modelObj;
2489c1cad2e7SMatthew G. Knepley   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
2490c1cad2e7SMatthew G. Knepley   Vec            coordinates;
2491c1cad2e7SMatthew G. Knepley   PetscScalar   *coords;
2492c1cad2e7SMatthew G. Knepley   PetscInt       bodyID, faceID, edgeID, vertexID;
2493c1cad2e7SMatthew G. Knepley   PetscInt       cdim, d, vStart, vEnd, v;
2494*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
2495c1cad2e7SMatthew G. Knepley #endif
2496c1cad2e7SMatthew G. Knepley 
2497c1cad2e7SMatthew G. Knepley   PetscFunctionBegin;
2498c1cad2e7SMatthew G. Knepley #if defined(PETSC_HAVE_EGADS)
24999566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
2500*5552b385SBrandon   if (!modelObj) {
2501*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
2502*5552b385SBrandon     islite = PETSC_TRUE;
2503*5552b385SBrandon   }
25043ba16761SJacob Faibussowitsch   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
25059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
25069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
25079566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
25089566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
25099566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
25109566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
25119566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
2512c1cad2e7SMatthew G. Knepley 
25139566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
2514*5552b385SBrandon 
2515*5552b385SBrandon   if (islite) {
2516*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
2517*5552b385SBrandon   } else {
25189566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
2519*5552b385SBrandon   }
2520c1cad2e7SMatthew G. Knepley 
25219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
25229566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(coordinates, &coords));
2523c1cad2e7SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
2524c1cad2e7SMatthew G. Knepley     PetscScalar *vcoords;
2525c1cad2e7SMatthew G. Knepley 
25269566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
25279566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
25289566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
25299566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
2530c1cad2e7SMatthew G. Knepley 
2531*5552b385SBrandon     PetscCheck(bodyID < Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bodyID, Nb);
2532*5552b385SBrandon     body = bodies[bodyID];
2533*5552b385SBrandon 
2534*5552b385SBrandon     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
2535*5552b385SBrandon     if (vertexID > 0) {
2536*5552b385SBrandon       if (islite) {
2537*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, NODE, vertexID, &vertex));
2538*5552b385SBrandon         PetscCall(EGlite_evaluate(vertex, NULL, result));
2539*5552b385SBrandon       } else {
2540*5552b385SBrandon         PetscCall(EG_objectBodyTopo(body, NODE, vertexID, &vertex));
2541*5552b385SBrandon         PetscCall(EG_evaluate(vertex, NULL, result));
2542*5552b385SBrandon       }
2543*5552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
2544*5552b385SBrandon     } else if (edgeID > 0) {
2545*5552b385SBrandon       /* Snap to EDGE at nearest location */
2546*5552b385SBrandon       double params[1];
2547*5552b385SBrandon       if (islite) {
2548*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
2549*5552b385SBrandon         PetscCall(EGlite_invEvaluate(edge, vcoords, params, result));
2550*5552b385SBrandon       } // Get (x,y,z) of nearest point on EDGE
2551*5552b385SBrandon       else {
2552*5552b385SBrandon         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
2553*5552b385SBrandon         PetscCall(EG_invEvaluate(edge, vcoords, params, result));
2554*5552b385SBrandon       }
2555*5552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
2556*5552b385SBrandon     } else if (faceID > 0) {
2557*5552b385SBrandon       /* Snap to FACE at nearest location */
2558*5552b385SBrandon       double params[2];
2559*5552b385SBrandon       if (islite) {
2560*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
2561*5552b385SBrandon         PetscCall(EGlite_invEvaluate(face, vcoords, params, result));
2562*5552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
2563*5552b385SBrandon       else {
2564*5552b385SBrandon         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
2565*5552b385SBrandon         PetscCall(EG_invEvaluate(face, vcoords, params, result));
2566*5552b385SBrandon       }
2567*5552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
2568*5552b385SBrandon     }
2569*5552b385SBrandon   }
2570*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
2571*5552b385SBrandon   /* Clear out global coordinates */
2572*5552b385SBrandon   PetscCall(VecDestroy(&dm->coordinates[0].x));
2573*5552b385SBrandon #endif
2574*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
2575*5552b385SBrandon }
2576*5552b385SBrandon 
2577*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
2578*5552b385SBrandon // This replaces the model in-place
2579*5552b385SBrandon PetscErrorCode ConvertGeomModelToAllBSplines(PetscBool islite, ego *model)
2580*5552b385SBrandon {
2581*5552b385SBrandon   /* EGADS/EGADSlite Variables */
2582*5552b385SBrandon   ego  context = NULL, geom, *bodies, *fobjs;
2583*5552b385SBrandon   int  oclass, mtype;
2584*5552b385SBrandon   int *senses;
2585*5552b385SBrandon   int  Nb, Nf;
2586*5552b385SBrandon 
2587*5552b385SBrandon   PetscFunctionBegin;
2588*5552b385SBrandon   // Get the number of bodies and body objects in the model
2589*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (*model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
2590*5552b385SBrandon   else PetscCallEGADS(EG_getTopology, (*model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
2591*5552b385SBrandon 
2592*5552b385SBrandon   // Get all Faces on the body    <-- Only working with 1 body at the moment.
2593*5552b385SBrandon   ego body = bodies[0];
2594*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
2595*5552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
2596*5552b385SBrandon   ego newGeom[Nf];
2597*5552b385SBrandon   ego newFaces[Nf];
2598*5552b385SBrandon 
2599*5552b385SBrandon   // Convert the 1st Face to a BSpline Geometry
2600*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
2601*5552b385SBrandon     ego     face = fobjs[ii];
2602*5552b385SBrandon     ego     gRef, gPrev, gNext, *lobjs;
2603*5552b385SBrandon     int     goclass, gmtype, *gpinfo;
2604*5552b385SBrandon     int     Nl, *lsenses;
2605*5552b385SBrandon     double *gprv;
2606*5552b385SBrandon     char   *gClass = (char *)"", *gType = (char *)"";
2607*5552b385SBrandon 
2608*5552b385SBrandon     /* Shape Optimization is NOT available for EGADSlite geometry files. */
2609*5552b385SBrandon     /*     Note :: islite options are left below in case future versions of EGADSlite includes this capability */
2610*5552b385SBrandon     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");
2611*5552b385SBrandon 
2612*5552b385SBrandon     if (islite) {
2613*5552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses)); // Get FACES Geometry object (geom_
2614*5552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));            // Get geometry object info
2615*5552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
2616*5552b385SBrandon     } // Get geometry info
2617*5552b385SBrandon     else {
2618*5552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses)); // Get FACES Geometry object (geom_
2619*5552b385SBrandon       PetscCallEGADS(EG_getGeometry, (geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));            // Get geometry object info
2620*5552b385SBrandon       PetscCallEGADS(EG_getInfo, (geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
2621*5552b385SBrandon     } // Get geometry info
2622*5552b385SBrandon 
2623*5552b385SBrandon     PetscCall(DMPlex_EGADS_GeomDecode_Internal(goclass, gmtype, &gClass, &gType)); // Decode Geometry integers
2624*5552b385SBrandon 
2625*5552b385SBrandon     // Convert current FACE to a BSpline Surface
2626*5552b385SBrandon     ego     bspline;
2627*5552b385SBrandon     ego     bRef, bPrev, bNext;
2628*5552b385SBrandon     int     boclass, bmtype, *bpinfo;
2629*5552b385SBrandon     double *bprv;
2630*5552b385SBrandon     char   *bClass = (char *)"", *bType = (char *)"";
2631*5552b385SBrandon 
2632*5552b385SBrandon     PetscCallEGADS(EG_convertToBSpline, (face, &bspline)); // Does not have an EGlite_ version
2633*5552b385SBrandon 
2634*5552b385SBrandon     if (islite) {
2635*5552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (bspline, &boclass, &bmtype, &bRef, &bpinfo, &bprv)); // Get geometry object info
2636*5552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (bspline, &boclass, &bmtype, &bRef, &bPrev, &bNext));
2637*5552b385SBrandon     } // Get geometry info
2638*5552b385SBrandon     else {
2639*5552b385SBrandon       PetscCallEGADS(EG_getGeometry, (bspline, &boclass, &bmtype, &bRef, &bpinfo, &bprv)); // Get geometry object info
2640*5552b385SBrandon       PetscCallEGADS(EG_getInfo, (bspline, &boclass, &bmtype, &bRef, &bPrev, &bNext));
2641*5552b385SBrandon     } // Get geometry info
2642*5552b385SBrandon 
2643*5552b385SBrandon     PetscCall(DMPlex_EGADS_GeomDecode_Internal(boclass, bmtype, &bClass, &bType)); // Decode Geometry integers
2644*5552b385SBrandon 
2645*5552b385SBrandon     // Get Context from FACE
2646*5552b385SBrandon     context = NULL;
2647*5552b385SBrandon     PetscCallEGADS(EG_getContext, (face, &context)); // Does not have an EGlite_ version
2648*5552b385SBrandon 
2649*5552b385SBrandon     // Silence WARNING Regarding OPENCASCADE 7.5
2650*5552b385SBrandon     if (islite) PetscCallEGADS(EGlite_setOutLevel, (context, 0));
2651*5552b385SBrandon     else PetscCallEGADS(EG_setOutLevel, (context, 0));
2652*5552b385SBrandon 
2653*5552b385SBrandon     ego newgeom;
2654*5552b385SBrandon     PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, bprv, &newgeom)); // Does not have an EGlite_ version
2655*5552b385SBrandon 
2656*5552b385SBrandon     PetscCallEGADS(EG_deleteObject, (bspline));
2657*5552b385SBrandon 
2658*5552b385SBrandon     // Create new FACE based on new SURFACE geometry
2659*5552b385SBrandon     double data[4];
2660*5552b385SBrandon     int    periodic;
2661*5552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, data, &periodic));
2662*5552b385SBrandon     else PetscCallEGADS(EG_getRange, (newgeom, data, &periodic));
2663*5552b385SBrandon 
2664*5552b385SBrandon     ego newface;
2665*5552b385SBrandon     PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, data, &newface)); // Does not have an EGlite_ version
2666*5552b385SBrandon     //PetscCallEGADS(EG_deleteObject, (newgeom));
2667*5552b385SBrandon     //PetscCallEGADS(EG_deleteObject, (newface));
2668*5552b385SBrandon     newFaces[ii] = newface;
2669*5552b385SBrandon     newGeom[ii]  = newgeom;
2670*5552b385SBrandon 
2671*5552b385SBrandon     // Reinstate WARNING Regarding OPENCASCADE 7.5
2672*5552b385SBrandon     if (islite) PetscCallEGADS(EGlite_setOutLevel, (context, 1));
2673*5552b385SBrandon     else PetscCallEGADS(EG_setOutLevel, (context, 1));
2674*5552b385SBrandon   }
2675*5552b385SBrandon 
2676*5552b385SBrandon   // Sew New Faces together to get a new model
2677*5552b385SBrandon   ego newmodel;
2678*5552b385SBrandon   PetscCallEGADS(EG_sewFaces, (Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version
2679*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
2680*5552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newFaces[ii]));
2681*5552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newGeom[ii]));
2682*5552b385SBrandon   }
2683*5552b385SBrandon   PetscCallEGADS(EG_deleteObject, (*model));
2684*5552b385SBrandon   *model = newmodel;
2685*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
2686*5552b385SBrandon }
2687*5552b385SBrandon #endif
2688*5552b385SBrandon 
2689*5552b385SBrandon /*@C
2690*5552b385SBrandon   DMPlexCreateGeomFromFile - Create a `DMPLEX` mesh from an EGADS, IGES, or STEP file.
2691*5552b385SBrandon 
2692*5552b385SBrandon   Collective
2693*5552b385SBrandon 
2694*5552b385SBrandon   Input Parameters:
2695*5552b385SBrandon + comm     - The MPI communicator
2696*5552b385SBrandon . filename - The name of the EGADS, IGES, or STEP file
2697*5552b385SBrandon - islite   - Flag for EGADSlite support
2698*5552b385SBrandon 
2699*5552b385SBrandon   Output Parameter:
2700*5552b385SBrandon . dm - The `DM` object representing the mesh
2701*5552b385SBrandon 
2702*5552b385SBrandon   Level: beginner
2703*5552b385SBrandon 
2704*5552b385SBrandon .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`, `DMPlexCreateEGADSliteFromFile()`
2705*5552b385SBrandon @*/
2706*5552b385SBrandon PetscErrorCode DMPlexCreateGeomFromFile(MPI_Comm comm, const char filename[], DM *dm, PetscBool islite)
2707*5552b385SBrandon {
2708*5552b385SBrandon   /* PETSc Variables */
2709*5552b385SBrandon   PetscMPIInt rank;
2710*5552b385SBrandon   PetscBool   printModel = PETSC_FALSE, tessModel = PETSC_FALSE, newModel = PETSC_FALSE;
2711*5552b385SBrandon   PetscBool   shapeOpt = PETSC_FALSE;
2712*5552b385SBrandon 
2713*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
2714*5552b385SBrandon   ego context = NULL, model = NULL;
2715*5552b385SBrandon #endif
2716*5552b385SBrandon 
2717*5552b385SBrandon   PetscFunctionBegin;
2718*5552b385SBrandon   PetscAssertPointer(filename, 2);
2719*5552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_print_model", &printModel, NULL));
2720*5552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_tess_model", &tessModel, NULL));
2721*5552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_new_model", &newModel, NULL));
2722*5552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_shape_opt", &shapeOpt, NULL));
2723*5552b385SBrandon   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2724*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
2725*5552b385SBrandon   if (rank == 0) {
2726*5552b385SBrandon     /* EGADSlite files cannot be used for Shape Optimization Work. It lacks the ability to make new geometry. */
2727*5552b385SBrandon     /* Must use EGADS, STEP, IGES or BRep files to perform this work.                                         */
2728*5552b385SBrandon     if (islite) {
2729*5552b385SBrandon       PetscCallEGADS(EGlite_open, (&context));
2730*5552b385SBrandon       PetscCallEGADS(EGlite_loadModel, (context, 0, filename, &model));
2731*5552b385SBrandon       if (shapeOpt) PetscCall(ConvertGeomModelToAllBSplines(islite, &model));
2732*5552b385SBrandon       if (printModel) PetscCall(DMPlexGeomPrintModel_Internal(model, islite));
2733*5552b385SBrandon     } else {
2734*5552b385SBrandon       PetscCallEGADS(EG_open, (&context));
2735*5552b385SBrandon       PetscCallEGADS(EG_loadModel, (context, 0, filename, &model));
2736*5552b385SBrandon       if (shapeOpt) PetscCall(ConvertGeomModelToAllBSplines(islite, &model));
2737*5552b385SBrandon       if (printModel) PetscCall(DMPlexGeomPrintModel_Internal(model, islite));
2738*5552b385SBrandon     }
2739*5552b385SBrandon   }
2740*5552b385SBrandon   if (tessModel) PetscCall(DMPlexCreateGeom_Tess_Internal(comm, context, model, dm, islite));
2741*5552b385SBrandon   else if (newModel) PetscCall(DMPlexCreateGeom_Internal(comm, context, model, dm, islite));
2742*5552b385SBrandon   else {
2743*5552b385SBrandon     PetscCall(DMPlexCreateGeom(comm, context, model, dm, islite));
2744*5552b385SBrandon   }
2745*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
2746*5552b385SBrandon #else
2747*5552b385SBrandon   SETERRQ(comm, PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
2748*5552b385SBrandon #endif
2749*5552b385SBrandon }
2750*5552b385SBrandon 
2751*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
2752*5552b385SBrandon /*@C
2753*5552b385SBrandon   DMPlex_Surface_Grad - Exposes the Geometry's Control Points and Weights and Calculates the Mesh Topology Boundary Nodes Gradient
2754*5552b385SBrandon                         with respect the associated geometry's Control Points and Weights.
2755*5552b385SBrandon 
2756*5552b385SBrandon                         // ----- Depreciated ---- See DMPlexGeomDataAndGrads ------ //
2757*5552b385SBrandon 
2758*5552b385SBrandon   Collective
2759*5552b385SBrandon 
2760*5552b385SBrandon   Input Parameters:
2761*5552b385SBrandon . dm      - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
2762*5552b385SBrandon 
2763*5552b385SBrandon   Output Parameter:
2764*5552b385SBrandon . 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
2765*5552b385SBrandon 
2766*5552b385SBrandon   Level: intermediate
2767*5552b385SBrandon 
2768*5552b385SBrandon .seealso:
2769*5552b385SBrandon @*/
2770*5552b385SBrandon PetscErrorCode DMPlex_Surface_Grad(DM dm)
2771*5552b385SBrandon {
2772*5552b385SBrandon   ego            model, geom, *bodies, *fobjs;
2773*5552b385SBrandon   PetscContainer modelObj;
2774*5552b385SBrandon   int            oclass, mtype, *senses;
2775*5552b385SBrandon   int            Nb, Nf;
2776*5552b385SBrandon   PetscHMapI     faceCntrlPtRow_Start = NULL, faceCPWeightsRow_Start = NULL;
2777*5552b385SBrandon   PetscHMapI     pointSurfGradRow_Start = NULL;
2778*5552b385SBrandon   Mat            pointSurfGrad;
2779*5552b385SBrandon   IS             faceLabelValues, edgeLabelValues, vertexLabelValues;
2780*5552b385SBrandon   PetscInt       faceLabelSize, edgeLabelSize, vertexLabelSize;
2781*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
2782*5552b385SBrandon 
2783*5552b385SBrandon   PetscFunctionBegin;
2784*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
2785*5552b385SBrandon   if (!modelObj) {
2786*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
2787*5552b385SBrandon     islite = PETSC_TRUE;
2788*5552b385SBrandon     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");
2789*5552b385SBrandon   }
2790*5552b385SBrandon 
2791*5552b385SBrandon   // Get attached EGADS model (pointer)
2792*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
2793*5552b385SBrandon 
2794*5552b385SBrandon   // Get the bodies in the model
2795*5552b385SBrandon   if (islite) {
2796*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
2797*5552b385SBrandon   } else {
2798*5552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
2799*5552b385SBrandon   }
2800*5552b385SBrandon 
2801*5552b385SBrandon   ego body = bodies[0]; // Only operate on 1st body. Model should only have 1 body.
2802*5552b385SBrandon 
2803*5552b385SBrandon   // Get the total number of FACEs in the model
2804*5552b385SBrandon   if (islite) {
2805*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
2806*5552b385SBrandon   } else {
2807*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
2808*5552b385SBrandon   }
2809*5552b385SBrandon 
2810*5552b385SBrandon   // Get the total number of points and IDs in the DMPlex with a "EGADS Face Label"
2811*5552b385SBrandon   // This will provide the total number of DMPlex points on the boundary of the geometry
2812*5552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Face ID", &faceLabelValues));
2813*5552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Face ID", &faceLabelSize));
2814*5552b385SBrandon 
2815*5552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Edge ID", &edgeLabelValues));
2816*5552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Edge ID", &edgeLabelSize));
2817*5552b385SBrandon 
2818*5552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Vertex ID", &vertexLabelValues));
2819*5552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Vertex ID", &vertexLabelSize));
2820*5552b385SBrandon 
2821*5552b385SBrandon   const PetscInt *faceIndices, *edgeIndices, *vertexIndices;
2822*5552b385SBrandon   PetscCall(ISGetIndices(faceLabelValues, &faceIndices));
2823*5552b385SBrandon   PetscCall(ISGetIndices(edgeLabelValues, &edgeIndices));
2824*5552b385SBrandon   PetscCall(ISGetIndices(vertexLabelValues, &vertexIndices));
2825*5552b385SBrandon 
2826*5552b385SBrandon   // Get the points associated with each FACE, EDGE and VERTEX label in the DM
2827*5552b385SBrandon   PetscInt totalNumPoints = 0;
2828*5552b385SBrandon   for (int ii = 0; ii < faceLabelSize; ++ii) {
2829*5552b385SBrandon     // Cycle through FACE labels
2830*5552b385SBrandon     PetscInt size;
2831*5552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Face ID", faceIndices[ii], &size));
2832*5552b385SBrandon     totalNumPoints += size;
2833*5552b385SBrandon   }
2834*5552b385SBrandon   PetscCall(ISRestoreIndices(faceLabelValues, &faceIndices));
2835*5552b385SBrandon   PetscCall(ISDestroy(&faceLabelValues));
2836*5552b385SBrandon 
2837*5552b385SBrandon   for (int ii = 0; ii < edgeLabelSize; ++ii) {
2838*5552b385SBrandon     // Cycle Through EDGE Labels
2839*5552b385SBrandon     PetscInt size;
2840*5552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Edge ID", edgeIndices[ii], &size));
2841*5552b385SBrandon     totalNumPoints += size;
2842*5552b385SBrandon   }
2843*5552b385SBrandon   PetscCall(ISRestoreIndices(edgeLabelValues, &edgeIndices));
2844*5552b385SBrandon   PetscCall(ISDestroy(&edgeLabelValues));
2845*5552b385SBrandon 
2846*5552b385SBrandon   for (int ii = 0; ii < vertexLabelSize; ++ii) {
2847*5552b385SBrandon     // Cycle Through VERTEX Labels
2848*5552b385SBrandon     PetscInt size;
2849*5552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Vertex ID", vertexIndices[ii], &size));
2850*5552b385SBrandon     totalNumPoints += size;
2851*5552b385SBrandon   }
2852*5552b385SBrandon   PetscCall(ISRestoreIndices(vertexLabelValues, &vertexIndices));
2853*5552b385SBrandon   PetscCall(ISDestroy(&vertexLabelValues));
2854*5552b385SBrandon 
2855*5552b385SBrandon   int     maxNumCPs   = 0;
2856*5552b385SBrandon   int     totalNumCPs = 0;
2857*5552b385SBrandon   ego     bRef, bPrev, bNext, fgeom, *lobjs;
2858*5552b385SBrandon   int     id, boclass, bmtype, *bpinfo;
2859*5552b385SBrandon   int     foclass, fmtype, Nl, *lsenses;
2860*5552b385SBrandon   double *bprv;
2861*5552b385SBrandon   double  fdata[4];
2862*5552b385SBrandon 
2863*5552b385SBrandon   // Create Hash Tables
2864*5552b385SBrandon   PetscInt cntr = 0, wcntr = 0;
2865*5552b385SBrandon   PetscCall(PetscHMapICreate(&faceCntrlPtRow_Start));
2866*5552b385SBrandon   PetscCall(PetscHMapICreate(&faceCPWeightsRow_Start));
2867*5552b385SBrandon 
2868*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
2869*5552b385SBrandon     // Need to get the maximum number of Control Points defining the FACEs
2870*5552b385SBrandon     ego face = fobjs[ii];
2871*5552b385SBrandon     int maxNumCPs_temp;
2872*5552b385SBrandon 
2873*5552b385SBrandon     if (islite) {
2874*5552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
2875*5552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
2876*5552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
2877*5552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
2878*5552b385SBrandon     } else {
2879*5552b385SBrandon       id = EG_indexBodyTopo(body, face);
2880*5552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
2881*5552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
2882*5552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
2883*5552b385SBrandon     }
2884*5552b385SBrandon 
2885*5552b385SBrandon     maxNumCPs_temp = bpinfo[2] * bpinfo[5];
2886*5552b385SBrandon     totalNumCPs += bpinfo[2] * bpinfo[5];
2887*5552b385SBrandon 
2888*5552b385SBrandon     if (maxNumCPs_temp > maxNumCPs) { maxNumCPs = maxNumCPs_temp; }
2889*5552b385SBrandon   }
2890*5552b385SBrandon 
2891*5552b385SBrandon   PetscInt *cpCoordDataLengthPtr, *wDataLengthPtr;
2892*5552b385SBrandon   PetscInt  cpCoordDataLength = 3 * totalNumCPs;
2893*5552b385SBrandon   PetscInt  wDataLength       = totalNumCPs;
2894*5552b385SBrandon   cpCoordDataLengthPtr        = &cpCoordDataLength;
2895*5552b385SBrandon   wDataLengthPtr              = &wDataLength;
2896*5552b385SBrandon   PetscScalar *cntrlPtCoords, *cntrlPtWeights;
2897*5552b385SBrandon   PetscMalloc1(cpCoordDataLength, &cntrlPtCoords);
2898*5552b385SBrandon   PetscMalloc1(wDataLength, &cntrlPtWeights);
2899*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
2900*5552b385SBrandon     // Need to Populate Control Point Coordinates and Weight Vectors
2901*5552b385SBrandon     ego           face = fobjs[ii];
2902*5552b385SBrandon     PetscHashIter hashKeyIter, wHashKeyIter;
2903*5552b385SBrandon     PetscBool     hashKeyFound, wHashKeyFound;
2904*5552b385SBrandon 
2905*5552b385SBrandon     if (islite) {
2906*5552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
2907*5552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
2908*5552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
2909*5552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
2910*5552b385SBrandon     } else {
2911*5552b385SBrandon       id = EG_indexBodyTopo(body, face);
2912*5552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
2913*5552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
2914*5552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
2915*5552b385SBrandon     }
2916*5552b385SBrandon 
2917*5552b385SBrandon     // Store Face ID to 1st Row of Control Point Vector
2918*5552b385SBrandon     PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, id, &hashKeyIter, &hashKeyFound));
2919*5552b385SBrandon 
2920*5552b385SBrandon     if (!hashKeyFound) { PetscCall(PetscHMapISet(faceCntrlPtRow_Start, id, cntr)); }
2921*5552b385SBrandon 
2922*5552b385SBrandon     int offsetCoord = bpinfo[3] + bpinfo[6];
2923*5552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; ++jj) {
2924*5552b385SBrandon       cntrlPtCoords[cntr] = bprv[offsetCoord + jj];
2925*5552b385SBrandon       cntr += 1;
2926*5552b385SBrandon     }
2927*5552b385SBrandon 
2928*5552b385SBrandon     // Store Face ID to 1st Row of Control Point Weight Vector
2929*5552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, id, &wHashKeyIter, &wHashKeyFound));
2930*5552b385SBrandon 
2931*5552b385SBrandon     if (!wHashKeyFound) { PetscCall(PetscHMapISet(faceCPWeightsRow_Start, id, wcntr)); }
2932*5552b385SBrandon 
2933*5552b385SBrandon     int offsetWeight = bpinfo[3] + bpinfo[6] + (3 * bpinfo[2] * bpinfo[5]);
2934*5552b385SBrandon     for (int jj = 0; jj < bpinfo[2] * bpinfo[5]; ++jj) {
2935*5552b385SBrandon       cntrlPtWeights[wcntr] = bprv[offsetWeight + jj];
2936*5552b385SBrandon       wcntr += 1;
2937*5552b385SBrandon     }
2938*5552b385SBrandon   }
2939*5552b385SBrandon 
2940*5552b385SBrandon   // Attach Control Point and Weight Data to DM
2941*5552b385SBrandon   {
2942*5552b385SBrandon     PetscContainer cpOrgObj, cpCoordObj, cpCoordLengthObj;
2943*5552b385SBrandon     PetscContainer wOrgObj, wValObj, wDataLengthObj;
2944*5552b385SBrandon 
2945*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpOrgObj));
2946*5552b385SBrandon     PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
2947*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Hash Table", (PetscObject)cpOrgObj));
2948*5552b385SBrandon     PetscCall(PetscContainerDestroy(&cpOrgObj));
2949*5552b385SBrandon 
2950*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordObj));
2951*5552b385SBrandon     PetscCall(PetscContainerSetPointer(cpCoordObj, cntrlPtCoords));
2952*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinates", (PetscObject)cpCoordObj));
2953*5552b385SBrandon     PetscCall(PetscContainerDestroy(&cpCoordObj));
2954*5552b385SBrandon 
2955*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordLengthObj));
2956*5552b385SBrandon     PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
2957*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject)cpCoordLengthObj));
2958*5552b385SBrandon     PetscCall(PetscContainerDestroy(&cpCoordLengthObj));
2959*5552b385SBrandon 
2960*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wOrgObj));
2961*5552b385SBrandon     PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
2962*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject)wOrgObj));
2963*5552b385SBrandon     PetscCall(PetscContainerDestroy(&wOrgObj));
2964*5552b385SBrandon 
2965*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wValObj));
2966*5552b385SBrandon     PetscCall(PetscContainerSetPointer(wValObj, cntrlPtWeights));
2967*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data", (PetscObject)wValObj));
2968*5552b385SBrandon     PetscCall(PetscContainerDestroy(&wValObj));
2969*5552b385SBrandon 
2970*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wDataLengthObj));
2971*5552b385SBrandon     PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
2972*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data Length", (PetscObject)wDataLengthObj));
2973*5552b385SBrandon     PetscCall(PetscContainerDestroy(&wDataLengthObj));
2974*5552b385SBrandon   }
2975*5552b385SBrandon 
2976*5552b385SBrandon   // Define Matrix to store  Surface Gradient information dx_i/dCPj_i
2977*5552b385SBrandon   PetscInt       gcntr   = 0;
2978*5552b385SBrandon   const PetscInt rowSize = 3 * maxNumCPs * totalNumPoints;
2979*5552b385SBrandon   const PetscInt colSize = 4 * Nf;
2980*5552b385SBrandon 
2981*5552b385SBrandon   // Create Point Surface Gradient Matrix
2982*5552b385SBrandon   MatCreate(PETSC_COMM_WORLD, &pointSurfGrad);
2983*5552b385SBrandon   MatSetSizes(pointSurfGrad, PETSC_DECIDE, PETSC_DECIDE, rowSize, colSize);
2984*5552b385SBrandon   MatSetType(pointSurfGrad, MATAIJ);
2985*5552b385SBrandon   MatSetUp(pointSurfGrad);
2986*5552b385SBrandon 
2987*5552b385SBrandon   // Create Hash Table to store Point's stare row in surfaceGrad[][]
2988*5552b385SBrandon   PetscCall(PetscHMapICreate(&pointSurfGradRow_Start));
2989*5552b385SBrandon 
2990*5552b385SBrandon   // Get Coordinates for the DMPlex point
2991*5552b385SBrandon   DM           cdm;
2992*5552b385SBrandon   PetscInt     dE, Nv;
2993*5552b385SBrandon   Vec          coordinatesLocal;
2994*5552b385SBrandon   PetscScalar *coords = NULL;
2995*5552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
2996*5552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &dE));
2997*5552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
2998*5552b385SBrandon 
2999*5552b385SBrandon   // CYCLE THROUGH FACEs
3000*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
3001*5552b385SBrandon     ego             face = fobjs[ii];
3002*5552b385SBrandon     ego            *eobjs, *nobjs;
3003*5552b385SBrandon     PetscInt        fid, Ne, Nn;
3004*5552b385SBrandon     DMLabel         faceLabel, edgeLabel, nodeLabel;
3005*5552b385SBrandon     PetscHMapI      currFaceUniquePoints = NULL;
3006*5552b385SBrandon     IS              facePoints, edgePoints, nodePoints;
3007*5552b385SBrandon     const PetscInt *fIndices, *eIndices, *nIndices;
3008*5552b385SBrandon     PetscInt        fSize, eSize, nSize;
3009*5552b385SBrandon     PetscHashIter   fHashKeyIter, eHashKeyIter, nHashKeyIter, pHashKeyIter;
3010*5552b385SBrandon     PetscBool       fHashKeyFound, eHashKeyFound, nHashKeyFound, pHashKeyFound;
3011*5552b385SBrandon     PetscInt        cfCntr = 0;
3012*5552b385SBrandon 
3013*5552b385SBrandon     // Get Geometry Object for the Current FACE
3014*5552b385SBrandon     if (islite) {
3015*5552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3016*5552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3017*5552b385SBrandon     } else {
3018*5552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3019*5552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3020*5552b385SBrandon     }
3021*5552b385SBrandon 
3022*5552b385SBrandon     // Get all EDGE and NODE objects attached to the current FACE
3023*5552b385SBrandon     if (islite) {
3024*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
3025*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, NODE, &Nn, &nobjs));
3026*5552b385SBrandon     } else {
3027*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
3028*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, NODE, &Nn, &nobjs));
3029*5552b385SBrandon     }
3030*5552b385SBrandon 
3031*5552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Face ID" and store them in a Hash Table for later use
3032*5552b385SBrandon     if (islite) {
3033*5552b385SBrandon       fid = EGlite_indexBodyTopo(body, face);
3034*5552b385SBrandon     } else {
3035*5552b385SBrandon       fid = EG_indexBodyTopo(body, face);
3036*5552b385SBrandon     }
3037*5552b385SBrandon 
3038*5552b385SBrandon     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
3039*5552b385SBrandon     PetscCall(DMLabelGetStratumIS(faceLabel, fid, &facePoints));
3040*5552b385SBrandon     PetscCall(ISGetIndices(facePoints, &fIndices));
3041*5552b385SBrandon     PetscCall(ISGetSize(facePoints, &fSize));
3042*5552b385SBrandon 
3043*5552b385SBrandon     PetscCall(PetscHMapICreate(&currFaceUniquePoints));
3044*5552b385SBrandon 
3045*5552b385SBrandon     for (int jj = 0; jj < fSize; ++jj) {
3046*5552b385SBrandon       PetscCall(PetscHMapIFind(currFaceUniquePoints, fIndices[jj], &fHashKeyIter, &fHashKeyFound));
3047*5552b385SBrandon 
3048*5552b385SBrandon       if (!fHashKeyFound) {
3049*5552b385SBrandon         PetscCall(PetscHMapISet(currFaceUniquePoints, fIndices[jj], cfCntr));
3050*5552b385SBrandon         cfCntr += 1;
3051*5552b385SBrandon       }
3052*5552b385SBrandon 
3053*5552b385SBrandon       PetscCall(PetscHMapIFind(pointSurfGradRow_Start, fIndices[jj], &pHashKeyIter, &pHashKeyFound));
3054*5552b385SBrandon 
3055*5552b385SBrandon       if (!pHashKeyFound) {
3056*5552b385SBrandon         PetscCall(PetscHMapISet(pointSurfGradRow_Start, fIndices[jj], gcntr));
3057*5552b385SBrandon         gcntr += 3 * maxNumCPs;
3058*5552b385SBrandon       }
3059*5552b385SBrandon     }
3060*5552b385SBrandon     PetscCall(ISRestoreIndices(facePoints, &fIndices));
3061*5552b385SBrandon     PetscCall(ISDestroy(&facePoints));
3062*5552b385SBrandon 
3063*5552b385SBrandon     // 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.
3064*5552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
3065*5552b385SBrandon       ego       edge = eobjs[jj];
3066*5552b385SBrandon       PetscBool containLabelValue;
3067*5552b385SBrandon 
3068*5552b385SBrandon       if (islite) {
3069*5552b385SBrandon         id = EGlite_indexBodyTopo(body, edge);
3070*5552b385SBrandon       } else {
3071*5552b385SBrandon         id = EG_indexBodyTopo(body, edge);
3072*5552b385SBrandon       }
3073*5552b385SBrandon 
3074*5552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
3075*5552b385SBrandon       PetscCall(DMLabelHasValue(edgeLabel, id, &containLabelValue));
3076*5552b385SBrandon 
3077*5552b385SBrandon       if (containLabelValue) {
3078*5552b385SBrandon         PetscCall(DMLabelGetStratumIS(edgeLabel, id, &edgePoints));
3079*5552b385SBrandon         PetscCall(ISGetIndices(edgePoints, &eIndices));
3080*5552b385SBrandon         PetscCall(ISGetSize(edgePoints, &eSize));
3081*5552b385SBrandon 
3082*5552b385SBrandon         for (int kk = 0; kk < eSize; ++kk) {
3083*5552b385SBrandon           PetscCall(PetscHMapIFind(currFaceUniquePoints, eIndices[kk], &eHashKeyIter, &eHashKeyFound));
3084*5552b385SBrandon 
3085*5552b385SBrandon           if (!eHashKeyFound) {
3086*5552b385SBrandon             PetscCall(PetscHMapISet(currFaceUniquePoints, eIndices[kk], cfCntr));
3087*5552b385SBrandon             cfCntr += 1;
3088*5552b385SBrandon           }
3089*5552b385SBrandon 
3090*5552b385SBrandon           PetscCall(PetscHMapIFind(pointSurfGradRow_Start, eIndices[kk], &pHashKeyIter, &pHashKeyFound));
3091*5552b385SBrandon 
3092*5552b385SBrandon           if (!pHashKeyFound) {
3093*5552b385SBrandon             PetscCall(PetscHMapISet(pointSurfGradRow_Start, eIndices[kk], gcntr));
3094*5552b385SBrandon             gcntr += 3 * maxNumCPs;
3095*5552b385SBrandon           }
3096*5552b385SBrandon         }
3097*5552b385SBrandon         PetscCall(ISRestoreIndices(edgePoints, &eIndices));
3098*5552b385SBrandon         PetscCall(ISDestroy(&edgePoints));
3099*5552b385SBrandon       }
3100*5552b385SBrandon     }
3101*5552b385SBrandon 
3102*5552b385SBrandon     // 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.
3103*5552b385SBrandon     for (int jj = 0; jj < Nn; ++jj) {
3104*5552b385SBrandon       ego node = nobjs[jj];
3105*5552b385SBrandon 
3106*5552b385SBrandon       if (islite) {
3107*5552b385SBrandon         id = EGlite_indexBodyTopo(body, node);
3108*5552b385SBrandon       } else {
3109*5552b385SBrandon         id = EG_indexBodyTopo(body, node);
3110*5552b385SBrandon       }
3111*5552b385SBrandon 
3112*5552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &nodeLabel));
3113*5552b385SBrandon       PetscCall(DMLabelGetStratumIS(nodeLabel, id, &nodePoints));
3114*5552b385SBrandon       PetscCall(ISGetIndices(nodePoints, &nIndices));
3115*5552b385SBrandon       PetscCall(ISGetSize(nodePoints, &nSize));
3116*5552b385SBrandon 
3117*5552b385SBrandon       for (int kk = 0; kk < nSize; ++kk) {
3118*5552b385SBrandon         PetscCall(PetscHMapIFind(currFaceUniquePoints, nIndices[kk], &nHashKeyIter, &nHashKeyFound));
3119*5552b385SBrandon 
3120*5552b385SBrandon         if (!nHashKeyFound) {
3121*5552b385SBrandon           PetscCall(PetscHMapISet(currFaceUniquePoints, nIndices[kk], cfCntr));
3122*5552b385SBrandon           cfCntr += 1;
3123*5552b385SBrandon         }
3124*5552b385SBrandon 
3125*5552b385SBrandon         PetscCall(PetscHMapIFind(pointSurfGradRow_Start, nIndices[kk], &pHashKeyIter, &pHashKeyFound));
3126*5552b385SBrandon         if (!pHashKeyFound) {
3127*5552b385SBrandon           PetscCall(PetscHMapISet(pointSurfGradRow_Start, nIndices[kk], gcntr));
3128*5552b385SBrandon           gcntr += 3 * maxNumCPs;
3129*5552b385SBrandon         }
3130*5552b385SBrandon       }
3131*5552b385SBrandon       PetscCall(ISRestoreIndices(nodePoints, &nIndices));
3132*5552b385SBrandon       PetscCall(ISDestroy(&nodePoints));
3133*5552b385SBrandon     }
3134*5552b385SBrandon 
3135*5552b385SBrandon     // Get the Total Number of entries in the Hash Table
3136*5552b385SBrandon     PetscInt currFaceUPSize;
3137*5552b385SBrandon     PetscCall(PetscHMapIGetSize(currFaceUniquePoints, &currFaceUPSize));
3138*5552b385SBrandon 
3139*5552b385SBrandon     // Get Keys
3140*5552b385SBrandon     PetscInt currFaceUPKeys[currFaceUPSize], off = 0;
3141*5552b385SBrandon     PetscCall(PetscHMapIGetKeys(currFaceUniquePoints, &off, currFaceUPKeys));
3142*5552b385SBrandon 
3143*5552b385SBrandon     // Cycle through all points on the current FACE
3144*5552b385SBrandon     for (int jj = 0; jj < currFaceUPSize; ++jj) {
3145*5552b385SBrandon       PetscInt currPointID = currFaceUPKeys[jj];
3146*5552b385SBrandon       PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
3147*5552b385SBrandon 
3148*5552b385SBrandon       // Get UV position of FACE
3149*5552b385SBrandon       double params[2], range[4], eval[18];
3150*5552b385SBrandon       int    peri;
3151*5552b385SBrandon 
3152*5552b385SBrandon       if (islite) {
3153*5552b385SBrandon         PetscCall(EGlite_getRange(face, range, &peri));
3154*5552b385SBrandon       } else {
3155*5552b385SBrandon         PetscCall(EG_getRange(face, range, &peri));
3156*5552b385SBrandon       }
3157*5552b385SBrandon 
3158*5552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
3159*5552b385SBrandon 
3160*5552b385SBrandon       if (islite) {
3161*5552b385SBrandon         PetscCall(EGlite_evaluate(face, params, eval));
3162*5552b385SBrandon       } else {
3163*5552b385SBrandon         PetscCall(EG_evaluate(face, params, eval));
3164*5552b385SBrandon       }
3165*5552b385SBrandon 
3166*5552b385SBrandon       // Make a new SURFACE Geometry by changing the location of the Control Points
3167*5552b385SBrandon       int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
3168*5552b385SBrandon       double nbprv[prvSize];
3169*5552b385SBrandon 
3170*5552b385SBrandon       // Cycle through each Control Point
3171*5552b385SBrandon       double deltaCoord = 1.0E-4;
3172*5552b385SBrandon       int    offset     = bpinfo[3] + bpinfo[6];
3173*5552b385SBrandon       int    wOffset    = offset + (3 * bpinfo[2] * bpinfo[5]);
3174*5552b385SBrandon       for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) {
3175*5552b385SBrandon         // Cycle through each direction (x, then y, then z)
3176*5552b385SBrandon         for (int kk = 0; kk < 4; ++kk) {
3177*5552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
3178*5552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) { nbprv[mm] = bprv[mm]; }
3179*5552b385SBrandon 
3180*5552b385SBrandon           if (kk == 0) { //X
3181*5552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0] + deltaCoord;
3182*5552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
3183*5552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
3184*5552b385SBrandon           } else if (kk == 1) { //Y
3185*5552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
3186*5552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1] + deltaCoord;
3187*5552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
3188*5552b385SBrandon           } else if (kk == 2) { //Z
3189*5552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
3190*5552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
3191*5552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2] + deltaCoord;
3192*5552b385SBrandon           } else if (kk == 3) { // Weights
3193*5552b385SBrandon             nbprv[wOffset + ii] = bprv[wOffset + ii] + deltaCoord;
3194*5552b385SBrandon           } else {
3195*5552b385SBrandon             // currently do nothing
3196*5552b385SBrandon           }
3197*5552b385SBrandon 
3198*5552b385SBrandon           // Create New Surface Based on New Control Points or Weights
3199*5552b385SBrandon           ego newgeom, context;
3200*5552b385SBrandon           if (islite) {
3201*5552b385SBrandon             PetscCall(EGlite_open(&context));
3202*5552b385SBrandon             PetscCall(EGlite_setOutLevel(context, 0));
3203*5552b385SBrandon           } else {
3204*5552b385SBrandon             PetscCall(EG_open(&context));
3205*5552b385SBrandon             PetscCall(EG_setOutLevel(context, 0));
3206*5552b385SBrandon           }
3207*5552b385SBrandon 
3208*5552b385SBrandon           PetscCall(EG_makeGeometry(context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
3209*5552b385SBrandon 
3210*5552b385SBrandon           if (islite) {
3211*5552b385SBrandon             PetscCall(EGlite_setOutLevel(context, 1));
3212*5552b385SBrandon           } else {
3213*5552b385SBrandon             PetscCall(EG_setOutLevel(context, 1));
3214*5552b385SBrandon           }
3215*5552b385SBrandon 
3216*5552b385SBrandon           // Evaluate new (x, y, z) Point Position based on new Surface Definition
3217*5552b385SBrandon           double newCoords[18];
3218*5552b385SBrandon           if (islite) {
3219*5552b385SBrandon             PetscCall(EGlite_getRange(newgeom, range, &peri));
3220*5552b385SBrandon           } else {
3221*5552b385SBrandon             PetscCall(EG_getRange(newgeom, range, &peri));
3222*5552b385SBrandon           }
3223*5552b385SBrandon 
3224*5552b385SBrandon           PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, newgeom, range, 0, dE, params, islite));
3225*5552b385SBrandon 
3226*5552b385SBrandon           if (islite) {
3227*5552b385SBrandon             PetscCall(EGlite_evaluate(newgeom, params, newCoords));
3228*5552b385SBrandon           } else {
3229*5552b385SBrandon             PetscCall(EG_evaluate(newgeom, params, newCoords));
3230*5552b385SBrandon           }
3231*5552b385SBrandon 
3232*5552b385SBrandon           // Now Calculate the Surface Gradient for the change in x-component Control Point
3233*5552b385SBrandon           PetscScalar dxdCx = (newCoords[0] - coords[0]) / deltaCoord;
3234*5552b385SBrandon           PetscScalar dxdCy = (newCoords[1] - coords[1]) / deltaCoord;
3235*5552b385SBrandon           PetscScalar dxdCz = (newCoords[2] - coords[2]) / deltaCoord;
3236*5552b385SBrandon 
3237*5552b385SBrandon           // Store Gradient Information in surfaceGrad[][] Matrix
3238*5552b385SBrandon           PetscInt startRow;
3239*5552b385SBrandon           PetscCall(PetscHMapIGet(pointSurfGradRow_Start, currPointID, &startRow));
3240*5552b385SBrandon 
3241*5552b385SBrandon           // Store Results in Petsc Matrix
3242*5552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 0, ((fid - 1) * 4) + kk, dxdCx, INSERT_VALUES));
3243*5552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 1, ((fid - 1) * 4) + kk, dxdCy, INSERT_VALUES));
3244*5552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 2, ((fid - 1) * 4) + kk, dxdCz, INSERT_VALUES));
3245*5552b385SBrandon         }
3246*5552b385SBrandon         offset += 3;
3247*5552b385SBrandon       }
3248*5552b385SBrandon       PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
3249*5552b385SBrandon     }
3250*5552b385SBrandon   }
3251*5552b385SBrandon 
3252*5552b385SBrandon   // Assemble Point Surface Grad Matrix
3253*5552b385SBrandon   MatAssemblyBegin(pointSurfGrad, MAT_FINAL_ASSEMBLY);
3254*5552b385SBrandon   MatAssemblyEnd(pointSurfGrad, MAT_FINAL_ASSEMBLY);
3255*5552b385SBrandon 
3256*5552b385SBrandon   // Attach Surface Gradient Hash Table and Matrix to DM
3257*5552b385SBrandon   {
3258*5552b385SBrandon     PetscContainer surfGradOrgObj, surfGradObj;
3259*5552b385SBrandon 
3260*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradOrgObj));
3261*5552b385SBrandon     PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
3262*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject)surfGradOrgObj));
3263*5552b385SBrandon     PetscCall(PetscContainerDestroy(&surfGradOrgObj));
3264*5552b385SBrandon 
3265*5552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradObj));
3266*5552b385SBrandon     PetscCall(PetscContainerSetPointer(surfGradObj, pointSurfGrad));
3267*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Matrix", (PetscObject)surfGradObj));
3268*5552b385SBrandon     PetscCall(PetscContainerDestroy(&surfGradObj));
3269*5552b385SBrandon   }
3270*5552b385SBrandon   if (islite) EGlite_free(fobjs);
3271*5552b385SBrandon   else EG_free(fobjs);
3272*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
3273*5552b385SBrandon }
3274*5552b385SBrandon 
3275*5552b385SBrandon static PetscErrorCode DestroyHashMap(void **p)
3276*5552b385SBrandon {
3277*5552b385SBrandon   PetscFunctionBegin;
3278*5552b385SBrandon   PetscCall(PetscHMapIDestroy((PetscHMapI *)p));
3279*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
3280*5552b385SBrandon }
3281*5552b385SBrandon #endif
3282*5552b385SBrandon 
3283*5552b385SBrandon /*@C
3284*5552b385SBrandon   DMPlexGeomDataAndGrads - Exposes Control Points and Control Point Weights defining the underlying geometry allowing user manipulation of the geometry.
3285*5552b385SBrandon 
3286*5552b385SBrandon   Collective
3287*5552b385SBrandon 
3288*5552b385SBrandon   Input Parameters:
3289*5552b385SBrandon + dm           - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
3290*5552b385SBrandon - fullGeomGrad - PetscBool flag. Determines how the Surface Area and Volume Gradients wrt to Control Points and Control Point Weights are calculated.
3291*5552b385SBrandon                       PETSC_FALSE :: Surface Area Gradient wrt Control Points and Control Point Weights are calculated using the change in the local
3292*5552b385SBrandon                                      FACE changes (not the entire body). Volume Gradients are not calculated. Faster computations.
3293*5552b385SBrandon                       PETSC_TRUE  :: Surface Area Gradietn wrt to Control Points and Control Point Weights are calculated using the change observed in
3294*5552b385SBrandon                                      the entire solid body. Volume Gradients are calculated. Slower computation due to the need to generate a new solid
3295*5552b385SBrandon                                      body geometry for every Control Point and Control Point Weight change.
3296*5552b385SBrandon 
3297*5552b385SBrandon   Output Parameter:
3298*5552b385SBrandon . dm - The updated DM object representing the mesh with PetscContainers containing the Control Point, Control Point Weight and Gradient Data.
3299*5552b385SBrandon 
3300*5552b385SBrandon   Level: intermediate
3301*5552b385SBrandon 
3302*5552b385SBrandon   Note:
3303*5552b385SBrandon   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).
3304*5552b385SBrandon 
3305*5552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexModifyEGADSGeomModel()`
3306*5552b385SBrandon @*/
3307*5552b385SBrandon PetscErrorCode DMPlexGeomDataAndGrads(DM dm, PetscBool fullGeomGrad)
3308*5552b385SBrandon {
3309*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
3310*5552b385SBrandon   /* PETSc Variables */
3311*5552b385SBrandon   PetscContainer modelObj;
3312*5552b385SBrandon   PetscHMapI     faceCntrlPtRow_Start = NULL, faceCPWeightsRow_Start = NULL;
3313*5552b385SBrandon   PetscHMapI     pointSurfGradRow_Start = NULL;
3314*5552b385SBrandon   Mat            pointSurfGrad, cpEquiv;
3315*5552b385SBrandon   IS             faceLabelValues, edgeLabelValues, vertexLabelValues;
3316*5552b385SBrandon   PetscInt       faceLabelSize, edgeLabelSize, vertexLabelSize;
3317*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
3318*5552b385SBrandon   /* EGADS Variables */
3319*5552b385SBrandon   ego model, geom, *bodies, *fobjs = NULL;
3320*5552b385SBrandon   int oclass, mtype, *senses;
3321*5552b385SBrandon   int Nb, Nf;
3322*5552b385SBrandon #endif
3323*5552b385SBrandon 
3324*5552b385SBrandon   PetscFunctionBegin;
3325*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
3326*5552b385SBrandon 
3327*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
3328*5552b385SBrandon   if (!modelObj) {
3329*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
3330*5552b385SBrandon     PetscCheck(modelObj, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input DM must have attached EGADS Geometry Model");
3331*5552b385SBrandon     islite = PETSC_TRUE;
3332*5552b385SBrandon     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");
3333*5552b385SBrandon   }
3334*5552b385SBrandon 
3335*5552b385SBrandon   // Get attached EGADS model (pointer)
3336*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
3337*5552b385SBrandon 
3338*5552b385SBrandon   // Get the bodies in the model
3339*5552b385SBrandon   if (islite) {
3340*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
3341*5552b385SBrandon   } else {
3342*5552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
3343*5552b385SBrandon   }
3344*5552b385SBrandon 
3345*5552b385SBrandon   ego body = bodies[0]; // Only operate on 1st body. Model should only have 1 body.
3346*5552b385SBrandon 
3347*5552b385SBrandon   // Get the total number of FACEs in the model
3348*5552b385SBrandon   if (islite) {
3349*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
3350*5552b385SBrandon   } else {
3351*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
3352*5552b385SBrandon   }
3353*5552b385SBrandon 
3354*5552b385SBrandon   // Get the total number of points and IDs in the DMPlex with a "EGADS Face Label"
3355*5552b385SBrandon   // This will provide the total number of DMPlex points on the boundary of the geometry
3356*5552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Face ID", &faceLabelValues));
3357*5552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Face ID", &faceLabelSize));
3358*5552b385SBrandon 
3359*5552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Edge ID", &edgeLabelValues));
3360*5552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Edge ID", &edgeLabelSize));
3361*5552b385SBrandon 
3362*5552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Vertex ID", &vertexLabelValues));
3363*5552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Vertex ID", &vertexLabelSize));
3364*5552b385SBrandon 
3365*5552b385SBrandon   const PetscInt *faceIndices, *edgeIndices, *vertexIndices;
3366*5552b385SBrandon   PetscCall(ISGetIndices(faceLabelValues, &faceIndices));
3367*5552b385SBrandon   PetscCall(ISGetIndices(edgeLabelValues, &edgeIndices));
3368*5552b385SBrandon   PetscCall(ISGetIndices(vertexLabelValues, &vertexIndices));
3369*5552b385SBrandon 
3370*5552b385SBrandon   // Get the points associated with each FACE, EDGE and VERTEX label in the DM
3371*5552b385SBrandon   PetscInt totalNumPoints = 0;
3372*5552b385SBrandon   for (int f = 0; f < faceLabelSize; ++f) {
3373*5552b385SBrandon     // Cycle through FACE labels
3374*5552b385SBrandon     PetscInt size;
3375*5552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Face ID", faceIndices[f], &size));
3376*5552b385SBrandon     totalNumPoints += size;
3377*5552b385SBrandon   }
3378*5552b385SBrandon   PetscCall(ISRestoreIndices(faceLabelValues, &faceIndices));
3379*5552b385SBrandon   PetscCall(ISDestroy(&faceLabelValues));
3380*5552b385SBrandon 
3381*5552b385SBrandon   for (int e = 0; e < edgeLabelSize; ++e) {
3382*5552b385SBrandon     // Cycle Through EDGE Labels
3383*5552b385SBrandon     PetscInt size;
3384*5552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Edge ID", edgeIndices[e], &size));
3385*5552b385SBrandon     totalNumPoints += size;
3386*5552b385SBrandon   }
3387*5552b385SBrandon   PetscCall(ISRestoreIndices(edgeLabelValues, &edgeIndices));
3388*5552b385SBrandon   PetscCall(ISDestroy(&edgeLabelValues));
3389*5552b385SBrandon 
3390*5552b385SBrandon   for (int ii = 0; ii < vertexLabelSize; ++ii) {
3391*5552b385SBrandon     // Cycle Through VERTEX Labels
3392*5552b385SBrandon     PetscInt size;
3393*5552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Vertex ID", vertexIndices[ii], &size));
3394*5552b385SBrandon     totalNumPoints += size;
3395*5552b385SBrandon   }
3396*5552b385SBrandon   PetscCall(ISRestoreIndices(vertexLabelValues, &vertexIndices));
3397*5552b385SBrandon   PetscCall(ISDestroy(&vertexLabelValues));
3398*5552b385SBrandon 
3399*5552b385SBrandon   int     maxNumCPs   = 0;
3400*5552b385SBrandon   int     totalNumCPs = 0;
3401*5552b385SBrandon   ego     bRef, bPrev, bNext, fgeom, *lobjs;
3402*5552b385SBrandon   int     id, boclass, bmtype, *bpinfo;
3403*5552b385SBrandon   int     foclass, fmtype, Nl, *lsenses;
3404*5552b385SBrandon   double *bprv;
3405*5552b385SBrandon   double  fdata[4];
3406*5552b385SBrandon 
3407*5552b385SBrandon   // Create Hash Tables
3408*5552b385SBrandon   PetscInt cntr = 0, wcntr = 0, vcntr = 0;
3409*5552b385SBrandon   PetscCall(PetscHMapICreate(&faceCntrlPtRow_Start));
3410*5552b385SBrandon   PetscCall(PetscHMapICreate(&faceCPWeightsRow_Start));
3411*5552b385SBrandon 
3412*5552b385SBrandon   for (int f = 0; f < Nf; ++f) {
3413*5552b385SBrandon     // Need to get the maximum number of Control Points defining the FACEs
3414*5552b385SBrandon     ego face = fobjs[f];
3415*5552b385SBrandon     int maxNumCPs_temp;
3416*5552b385SBrandon 
3417*5552b385SBrandon     if (islite) {
3418*5552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
3419*5552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3420*5552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3421*5552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
3422*5552b385SBrandon     } else {
3423*5552b385SBrandon       id = EG_indexBodyTopo(body, face);
3424*5552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3425*5552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3426*5552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
3427*5552b385SBrandon     }
3428*5552b385SBrandon     maxNumCPs_temp = bpinfo[2] * bpinfo[5];
3429*5552b385SBrandon     totalNumCPs += bpinfo[2] * bpinfo[5];
3430*5552b385SBrandon 
3431*5552b385SBrandon     if (maxNumCPs_temp > maxNumCPs) { maxNumCPs = maxNumCPs_temp; }
3432*5552b385SBrandon   }
3433*5552b385SBrandon 
3434*5552b385SBrandon   PetscInt *cpCoordDataLengthPtr, *wDataLengthPtr;
3435*5552b385SBrandon   PetscInt  cpCoordDataLength = 3 * totalNumCPs;
3436*5552b385SBrandon   PetscInt  wDataLength       = totalNumCPs;
3437*5552b385SBrandon   cpCoordDataLengthPtr        = &cpCoordDataLength;
3438*5552b385SBrandon   wDataLengthPtr              = &wDataLength;
3439*5552b385SBrandon 
3440*5552b385SBrandon   Vec          cntrlPtCoordsVec, cntrlPtWeightsVec;
3441*5552b385SBrandon   PetscScalar *cntrlPtCoords, *cntrlPtWeights;
3442*5552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &cntrlPtCoordsVec));
3443*5552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &cntrlPtWeightsVec));
3444*5552b385SBrandon 
3445*5552b385SBrandon   // For dSA/dCPi
3446*5552b385SBrandon   Vec          gradSACPVec, gradSAWVec, gradVCPVec, gradVWVec;
3447*5552b385SBrandon   PetscScalar *gradSACP, *gradSAW, *gradVCP, *gradVW;
3448*5552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &gradSACPVec));
3449*5552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &gradSAWVec));
3450*5552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &gradVCPVec));
3451*5552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &gradVWVec));
3452*5552b385SBrandon 
3453*5552b385SBrandon   // Control Point - Vertex/Edge/Face Relationship
3454*5552b385SBrandon   PetscInt *cp_vertex, *cp_edge, *cp_face;
3455*5552b385SBrandon   PetscInt *w_vertex, *w_edge, *w_face;
3456*5552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_vertex));
3457*5552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_edge));
3458*5552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_face));
3459*5552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_vertex));
3460*5552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_edge));
3461*5552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_face));
3462*5552b385SBrandon 
3463*5552b385SBrandon   for (int f = 0; f < Nf; ++f) {
3464*5552b385SBrandon     // Need to Populate Control Point Coordinates and Weight Vectors
3465*5552b385SBrandon     ego           face = fobjs[f];
3466*5552b385SBrandon     ego          *vobjs, *eobjs;
3467*5552b385SBrandon     int           offsetCoord, offsetWeight;
3468*5552b385SBrandon     PetscInt      Nv, Ne, wRowStart = 0;
3469*5552b385SBrandon     PetscHashIter hashKeyIter, wHashKeyIter;
3470*5552b385SBrandon     PetscBool     hashKeyFound, wHashKeyFound;
3471*5552b385SBrandon 
3472*5552b385SBrandon     if (islite) {
3473*5552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
3474*5552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3475*5552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3476*5552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
3477*5552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (body, face, NODE, &Nv, &vobjs));
3478*5552b385SBrandon     } else {
3479*5552b385SBrandon       id = EG_indexBodyTopo(body, face);
3480*5552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3481*5552b385SBrandon       PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3482*5552b385SBrandon       PetscCallEGADS(EG_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
3483*5552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (body, face, NODE, &Nv, &vobjs));
3484*5552b385SBrandon     }
3485*5552b385SBrandon 
3486*5552b385SBrandon     // Store Face ID to 1st Row of Control Point Vector
3487*5552b385SBrandon     PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, id, &hashKeyIter, &hashKeyFound));
3488*5552b385SBrandon 
3489*5552b385SBrandon     if (!hashKeyFound) PetscCall(PetscHMapISet(faceCntrlPtRow_Start, id, cntr));
3490*5552b385SBrandon 
3491*5552b385SBrandon     PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, &cntrlPtCoords));
3492*5552b385SBrandon     offsetCoord = bpinfo[3] + bpinfo[6];
3493*5552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; ++jj) {
3494*5552b385SBrandon       cntrlPtCoords[cntr] = bprv[offsetCoord + jj];
3495*5552b385SBrandon       cntr += 1;
3496*5552b385SBrandon     }
3497*5552b385SBrandon 
3498*5552b385SBrandon     // Store Face ID to 1st Row of Control Point Weight Vector
3499*5552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, id, &wHashKeyIter, &wHashKeyFound));
3500*5552b385SBrandon 
3501*5552b385SBrandon     if (!wHashKeyFound) {
3502*5552b385SBrandon       PetscCall(PetscHMapISet(faceCPWeightsRow_Start, id, wcntr));
3503*5552b385SBrandon       wRowStart = wcntr;
3504*5552b385SBrandon     }
3505*5552b385SBrandon 
3506*5552b385SBrandon     PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, &cntrlPtWeights));
3507*5552b385SBrandon     offsetWeight = bpinfo[3] + bpinfo[6] + (3 * bpinfo[2] * bpinfo[5]);
3508*5552b385SBrandon     for (int jj = 0; jj < bpinfo[2] * bpinfo[5]; ++jj) {
3509*5552b385SBrandon       cntrlPtWeights[wcntr] = bprv[offsetWeight + jj];
3510*5552b385SBrandon       cp_face[wcntr]        = id;
3511*5552b385SBrandon       w_face[wcntr]         = id;
3512*5552b385SBrandon       wcntr += 1;
3513*5552b385SBrandon     }
3514*5552b385SBrandon     PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, &cntrlPtWeights));
3515*5552b385SBrandon 
3516*5552b385SBrandon     // Associate Control Points with Vertix IDs
3517*5552b385SBrandon     PetscScalar xcp, ycp, zcp;
3518*5552b385SBrandon     offsetCoord = bpinfo[3] + bpinfo[6];
3519*5552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; jj += 3) {
3520*5552b385SBrandon       xcp = bprv[offsetCoord + jj + 0];
3521*5552b385SBrandon       ycp = bprv[offsetCoord + jj + 1];
3522*5552b385SBrandon       zcp = bprv[offsetCoord + jj + 2];
3523*5552b385SBrandon 
3524*5552b385SBrandon       //Initialize Control Point and Weight to Vertex ID relationship to -1
3525*5552b385SBrandon       cp_vertex[vcntr] = -1;
3526*5552b385SBrandon       w_vertex[vcntr]  = -1;
3527*5552b385SBrandon       cp_edge[vcntr]   = -1;
3528*5552b385SBrandon       w_edge[vcntr]    = -1;
3529*5552b385SBrandon 
3530*5552b385SBrandon       for (int kk = 0; kk < Nv; ++kk) {
3531*5552b385SBrandon         int         vid;
3532*5552b385SBrandon         double      vCoords[3];
3533*5552b385SBrandon         PetscScalar vDelta;
3534*5552b385SBrandon         ego         vertex = vobjs[kk];
3535*5552b385SBrandon 
3536*5552b385SBrandon         if (islite) {
3537*5552b385SBrandon           vid = EGlite_indexBodyTopo(body, vertex);
3538*5552b385SBrandon           PetscCallEGADS(EGlite_evaluate, (vertex, NULL, vCoords));
3539*5552b385SBrandon         } else {
3540*5552b385SBrandon           vid = EG_indexBodyTopo(body, vertex);
3541*5552b385SBrandon           PetscCallEGADS(EG_evaluate, (vertex, NULL, vCoords));
3542*5552b385SBrandon         }
3543*5552b385SBrandon         vDelta = PetscSqrtReal(PetscSqr(vCoords[0] - xcp) + PetscSqr(vCoords[1] - ycp) + PetscSqr(vCoords[2] - zcp));
3544*5552b385SBrandon 
3545*5552b385SBrandon         if (vDelta < 1.0E-15) {
3546*5552b385SBrandon           cp_vertex[vcntr] = vid;
3547*5552b385SBrandon           w_vertex[vcntr]  = vid;
3548*5552b385SBrandon         }
3549*5552b385SBrandon       }
3550*5552b385SBrandon       vcntr += 1;
3551*5552b385SBrandon     }
3552*5552b385SBrandon     // These two line could be replaced with DMPlexFreeGeomObject()
3553*5552b385SBrandon     if (islite) EGlite_free(vobjs);
3554*5552b385SBrandon     else EG_free(vobjs);
3555*5552b385SBrandon 
3556*5552b385SBrandon     // Associate Control Points with Edge IDs
3557*5552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, face, EDGE, &Ne, &eobjs));
3558*5552b385SBrandon     else PetscCallEGADS(EG_getBodyTopos, (body, face, EDGE, &Ne, &eobjs));
3559*5552b385SBrandon 
3560*5552b385SBrandon     int cpV1, cpV2;
3561*5552b385SBrandon     int minID, maxID;
3562*5552b385SBrandon 
3563*5552b385SBrandon     // Along vmin axis
3564*5552b385SBrandon     minID = wRowStart;
3565*5552b385SBrandon     maxID = wRowStart + (bpinfo[2] - 1);
3566*5552b385SBrandon     cpV1  = cp_vertex[minID];
3567*5552b385SBrandon     cpV2  = cp_vertex[maxID];
3568*5552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
3569*5552b385SBrandon       ego edge = eobjs[jj];
3570*5552b385SBrandon       ego egeom, *nobjs;
3571*5552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
3572*5552b385SBrandon       int n1ID, n2ID, eid;
3573*5552b385SBrandon 
3574*5552b385SBrandon       if (islite) {
3575*5552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
3576*5552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3577*5552b385SBrandon       } else {
3578*5552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
3579*5552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3580*5552b385SBrandon       }
3581*5552b385SBrandon 
3582*5552b385SBrandon       if (emtype != DEGENERATE) {
3583*5552b385SBrandon         // Get IDs for current Edge's End Vertices
3584*5552b385SBrandon         if (islite) {
3585*5552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
3586*5552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
3587*5552b385SBrandon         } else {
3588*5552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
3589*5552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
3590*5552b385SBrandon         }
3591*5552b385SBrandon 
3592*5552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
3593*5552b385SBrandon           for (int kk = minID + 1; kk < maxID; ++kk) {
3594*5552b385SBrandon             cp_edge[kk] = eid;
3595*5552b385SBrandon             w_edge[kk]  = eid;
3596*5552b385SBrandon           }
3597*5552b385SBrandon         }
3598*5552b385SBrandon       }
3599*5552b385SBrandon     }
3600*5552b385SBrandon 
3601*5552b385SBrandon     // Along vmax axis
3602*5552b385SBrandon     minID = wRowStart + (bpinfo[2] * (bpinfo[5] - 1));
3603*5552b385SBrandon     maxID = wRowStart + (bpinfo[2] * bpinfo[5] - 1);
3604*5552b385SBrandon 
3605*5552b385SBrandon     cpV1 = cp_vertex[minID];
3606*5552b385SBrandon     cpV2 = cp_vertex[maxID];
3607*5552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
3608*5552b385SBrandon       ego edge = eobjs[jj];
3609*5552b385SBrandon       ego egeom, *nobjs;
3610*5552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
3611*5552b385SBrandon       int n1ID, n2ID, eid;
3612*5552b385SBrandon 
3613*5552b385SBrandon       if (islite) {
3614*5552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
3615*5552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3616*5552b385SBrandon       } else {
3617*5552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
3618*5552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3619*5552b385SBrandon       }
3620*5552b385SBrandon 
3621*5552b385SBrandon       if (emtype != DEGENERATE) {
3622*5552b385SBrandon         // Get IDs for current Edge's End Vertices
3623*5552b385SBrandon         if (islite) {
3624*5552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
3625*5552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
3626*5552b385SBrandon         } else {
3627*5552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
3628*5552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
3629*5552b385SBrandon         }
3630*5552b385SBrandon 
3631*5552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
3632*5552b385SBrandon           for (int kk = minID + 1; kk < maxID - 1; ++kk) {
3633*5552b385SBrandon             cp_edge[kk] = eid;
3634*5552b385SBrandon             w_edge[kk]  = eid;
3635*5552b385SBrandon           }
3636*5552b385SBrandon         }
3637*5552b385SBrandon       }
3638*5552b385SBrandon     }
3639*5552b385SBrandon 
3640*5552b385SBrandon     // Along umin axis
3641*5552b385SBrandon     minID = wRowStart;
3642*5552b385SBrandon     maxID = wRowStart + (bpinfo[2] * (bpinfo[5] - 1));
3643*5552b385SBrandon 
3644*5552b385SBrandon     cpV1 = cp_vertex[minID];
3645*5552b385SBrandon     cpV2 = cp_vertex[maxID];
3646*5552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
3647*5552b385SBrandon       ego edge = eobjs[jj];
3648*5552b385SBrandon       ego egeom, *nobjs;
3649*5552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
3650*5552b385SBrandon       int n1ID, n2ID, eid;
3651*5552b385SBrandon 
3652*5552b385SBrandon       if (islite) {
3653*5552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
3654*5552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3655*5552b385SBrandon       } else {
3656*5552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
3657*5552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3658*5552b385SBrandon       }
3659*5552b385SBrandon 
3660*5552b385SBrandon       if (emtype != DEGENERATE) {
3661*5552b385SBrandon         // Get IDs for current Edge's End Vertices
3662*5552b385SBrandon         if (islite) {
3663*5552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
3664*5552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
3665*5552b385SBrandon         } else {
3666*5552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
3667*5552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
3668*5552b385SBrandon         }
3669*5552b385SBrandon 
3670*5552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
3671*5552b385SBrandon           for (int kk = minID + bpinfo[2]; kk < maxID; kk += bpinfo[2]) {
3672*5552b385SBrandon             cp_edge[kk] = eid;
3673*5552b385SBrandon             w_edge[kk]  = eid;
3674*5552b385SBrandon           }
3675*5552b385SBrandon         }
3676*5552b385SBrandon       }
3677*5552b385SBrandon     }
3678*5552b385SBrandon 
3679*5552b385SBrandon     // Along umax axis
3680*5552b385SBrandon     minID = wRowStart + (bpinfo[2] - 1);
3681*5552b385SBrandon     maxID = wRowStart + (bpinfo[2] * bpinfo[5]) - 1;
3682*5552b385SBrandon     cpV1  = cp_vertex[minID];
3683*5552b385SBrandon     cpV2  = cp_vertex[maxID];
3684*5552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
3685*5552b385SBrandon       ego edge = eobjs[jj];
3686*5552b385SBrandon       ego egeom, *nobjs;
3687*5552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
3688*5552b385SBrandon       int n1ID, n2ID, eid;
3689*5552b385SBrandon 
3690*5552b385SBrandon       if (islite) {
3691*5552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
3692*5552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3693*5552b385SBrandon       } else {
3694*5552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
3695*5552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
3696*5552b385SBrandon       }
3697*5552b385SBrandon 
3698*5552b385SBrandon       if (emtype != DEGENERATE) {
3699*5552b385SBrandon         // Get IDs for current Edge's End Vertices
3700*5552b385SBrandon         if (islite) {
3701*5552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
3702*5552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
3703*5552b385SBrandon         } else {
3704*5552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
3705*5552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
3706*5552b385SBrandon         }
3707*5552b385SBrandon 
3708*5552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
3709*5552b385SBrandon           for (int kk = minID + bpinfo[2]; kk < maxID; kk += bpinfo[2]) {
3710*5552b385SBrandon             cp_edge[kk] = eid;
3711*5552b385SBrandon             w_edge[kk]  = eid;
3712*5552b385SBrandon           }
3713*5552b385SBrandon         }
3714*5552b385SBrandon       }
3715*5552b385SBrandon     }
3716*5552b385SBrandon     // These two lines could be replaced with DMPlexFreeGeomObject()
3717*5552b385SBrandon     if (islite) EGlite_free(eobjs);
3718*5552b385SBrandon     else EG_free(eobjs);
3719*5552b385SBrandon   }
3720*5552b385SBrandon 
3721*5552b385SBrandon   // Determine Control Point Equivalance Matrix relating Control Points between Surfaces
3722*5552b385SBrandon   //     Note: The Weights will also be tied together in the same manner
3723*5552b385SBrandon   //           Also can use the Weight Hash Table for Row Start ID of each Face
3724*5552b385SBrandon   const PetscInt cpRowSize = totalNumCPs;
3725*5552b385SBrandon   const PetscInt cpColSize = cpRowSize;
3726*5552b385SBrandon   PetscInt      *maxNumRelatePtr;
3727*5552b385SBrandon   PetscInt       maxNumRelate = 0;
3728*5552b385SBrandon 
3729*5552b385SBrandon   // Create Point Surface Gradient Matrix
3730*5552b385SBrandon   PetscCall(MatCreate(PETSC_COMM_WORLD, &cpEquiv));
3731*5552b385SBrandon   PetscCall(MatSetSizes(cpEquiv, PETSC_DECIDE, PETSC_DECIDE, cpRowSize, cpColSize));
3732*5552b385SBrandon   PetscCall(MatSetType(cpEquiv, MATAIJ));
3733*5552b385SBrandon   PetscCall(MatSetUp(cpEquiv));
3734*5552b385SBrandon 
3735*5552b385SBrandon   for (int ii = 0; ii < totalNumCPs; ++ii) {
3736*5552b385SBrandon     PetscScalar x1, y1, z1;
3737*5552b385SBrandon     PetscInt    maxRelateTemp = 0;
3738*5552b385SBrandon 
3739*5552b385SBrandon     x1 = cntrlPtCoords[(3 * ii) + 0];
3740*5552b385SBrandon     y1 = cntrlPtCoords[(3 * ii) + 1];
3741*5552b385SBrandon     z1 = cntrlPtCoords[(3 * ii) + 2];
3742*5552b385SBrandon 
3743*5552b385SBrandon     for (int jj = 0; jj < totalNumCPs; ++jj) {
3744*5552b385SBrandon       PetscScalar x2, y2, z2;
3745*5552b385SBrandon       PetscScalar cpDelta, eqFactor;
3746*5552b385SBrandon       x2 = cntrlPtCoords[(3 * jj) + 0];
3747*5552b385SBrandon       y2 = cntrlPtCoords[(3 * jj) + 1];
3748*5552b385SBrandon       z2 = cntrlPtCoords[(3 * jj) + 2];
3749*5552b385SBrandon 
3750*5552b385SBrandon       cpDelta = PetscSqrtReal(PetscSqr(x2 - x1) + PetscSqr(y2 - y1) + PetscSqr(z2 - z1));
3751*5552b385SBrandon       if (cpDelta < 1.0E-15) {
3752*5552b385SBrandon         eqFactor = 1.0;
3753*5552b385SBrandon         maxRelateTemp += 1;
3754*5552b385SBrandon       } else {
3755*5552b385SBrandon         eqFactor = 0.0;
3756*5552b385SBrandon       }
3757*5552b385SBrandon 
3758*5552b385SBrandon       // Store Results in Petsc Matrix
3759*5552b385SBrandon       PetscCall(MatSetValue(cpEquiv, ii, jj, eqFactor, INSERT_VALUES));
3760*5552b385SBrandon     }
3761*5552b385SBrandon     if (maxRelateTemp > maxNumRelate) maxNumRelate = maxRelateTemp;
3762*5552b385SBrandon   }
3763*5552b385SBrandon   maxNumRelatePtr = &maxNumRelate;
3764*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, &cntrlPtCoords));
3765*5552b385SBrandon 
3766*5552b385SBrandon   // Assemble Point Surface Grad Matrix
3767*5552b385SBrandon   PetscCall(MatAssemblyBegin(cpEquiv, MAT_FINAL_ASSEMBLY));
3768*5552b385SBrandon   PetscCall(MatAssemblyEnd(cpEquiv, MAT_FINAL_ASSEMBLY));
3769*5552b385SBrandon 
3770*5552b385SBrandon   // Attach Control Point and Weight Data to DM
3771*5552b385SBrandon   {
3772*5552b385SBrandon     PetscContainer cpOrgObj, cpCoordLengthObj;
3773*5552b385SBrandon     PetscContainer wOrgObj, wDataLengthObj;
3774*5552b385SBrandon     PetscContainer cp_faceObj, cp_edgeObj, cp_vertexObj;
3775*5552b385SBrandon     PetscContainer w_faceObj, w_edgeObj, w_vertexObj;
3776*5552b385SBrandon     PetscContainer maxNumRelateObj;
3777*5552b385SBrandon 
3778*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpOrgObj));
3779*5552b385SBrandon     if (!cpOrgObj) {
3780*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpOrgObj));
3781*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
3782*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Hash Table", (PetscObject)cpOrgObj));
3783*5552b385SBrandon       PetscCall(PetscContainerDestroy(&cpOrgObj));
3784*5552b385SBrandon     } else {
3785*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
3786*5552b385SBrandon     }
3787*5552b385SBrandon 
3788*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinates", (PetscObject)cntrlPtCoordsVec));
3789*5552b385SBrandon     PetscCall(VecDestroy(&cntrlPtCoordsVec));
3790*5552b385SBrandon 
3791*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordLengthObj));
3792*5552b385SBrandon     if (!cpCoordLengthObj) {
3793*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordLengthObj));
3794*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
3795*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject)cpCoordLengthObj));
3796*5552b385SBrandon       PetscCall(PetscContainerDestroy(&cpCoordLengthObj));
3797*5552b385SBrandon     } else {
3798*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
3799*5552b385SBrandon     }
3800*5552b385SBrandon 
3801*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wOrgObj));
3802*5552b385SBrandon     if (!wOrgObj) {
3803*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wOrgObj));
3804*5552b385SBrandon       PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
3805*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject)wOrgObj));
3806*5552b385SBrandon       PetscCall(PetscContainerDestroy(&wOrgObj));
3807*5552b385SBrandon     } else {
3808*5552b385SBrandon       PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
3809*5552b385SBrandon     }
3810*5552b385SBrandon 
3811*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data", (PetscObject)cntrlPtWeightsVec));
3812*5552b385SBrandon     PetscCall(VecDestroy(&cntrlPtWeightsVec));
3813*5552b385SBrandon 
3814*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
3815*5552b385SBrandon     if (!wDataLengthObj) {
3816*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wDataLengthObj));
3817*5552b385SBrandon       PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
3818*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data Length", (PetscObject)wDataLengthObj));
3819*5552b385SBrandon       PetscCall(PetscContainerDestroy(&wDataLengthObj));
3820*5552b385SBrandon     } else {
3821*5552b385SBrandon       PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
3822*5552b385SBrandon     }
3823*5552b385SBrandon 
3824*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Equivalancy Matrix", (PetscObject)cpEquiv));
3825*5552b385SBrandon 
3826*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject *)&maxNumRelateObj));
3827*5552b385SBrandon     if (!maxNumRelateObj) {
3828*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &maxNumRelateObj));
3829*5552b385SBrandon       PetscCall(PetscContainerSetPointer(maxNumRelateObj, maxNumRelatePtr));
3830*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject)maxNumRelateObj));
3831*5552b385SBrandon       PetscCall(PetscContainerDestroy(&maxNumRelateObj));
3832*5552b385SBrandon     } else {
3833*5552b385SBrandon       PetscCall(PetscContainerSetPointer(maxNumRelateObj, maxNumRelatePtr));
3834*5552b385SBrandon     }
3835*5552b385SBrandon 
3836*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Face Map", (PetscObject *)&cp_faceObj));
3837*5552b385SBrandon     if (!cp_faceObj) {
3838*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_faceObj));
3839*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_faceObj, cp_face));
3840*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_faceObj, PetscCtxDestroyDefault));
3841*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Face Map", (PetscObject)cp_faceObj));
3842*5552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_faceObj));
3843*5552b385SBrandon     } else {
3844*5552b385SBrandon       void *tmp;
3845*5552b385SBrandon 
3846*5552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_faceObj, &tmp));
3847*5552b385SBrandon       PetscCall(PetscFree(tmp));
3848*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_faceObj, cp_face));
3849*5552b385SBrandon     }
3850*5552b385SBrandon 
3851*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject *)&w_faceObj));
3852*5552b385SBrandon     if (!w_faceObj) {
3853*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_faceObj));
3854*5552b385SBrandon       PetscCall(PetscContainerSetPointer(w_faceObj, w_face));
3855*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_faceObj, PetscCtxDestroyDefault));
3856*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject)w_faceObj));
3857*5552b385SBrandon       PetscCall(PetscContainerDestroy(&w_faceObj));
3858*5552b385SBrandon     } else {
3859*5552b385SBrandon       void *tmp;
3860*5552b385SBrandon 
3861*5552b385SBrandon       PetscCall(PetscContainerGetPointer(w_faceObj, &tmp));
3862*5552b385SBrandon       PetscCall(PetscFree(tmp));
3863*5552b385SBrandon       PetscCall(PetscContainerSetPointer(w_faceObj, w_face));
3864*5552b385SBrandon     }
3865*5552b385SBrandon 
3866*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Edge Map", (PetscObject *)&cp_edgeObj));
3867*5552b385SBrandon     if (!cp_edgeObj) {
3868*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_edgeObj));
3869*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_edgeObj, cp_edge));
3870*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_edgeObj, PetscCtxDestroyDefault));
3871*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Edge Map", (PetscObject)cp_edgeObj));
3872*5552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_edgeObj));
3873*5552b385SBrandon     } else {
3874*5552b385SBrandon       void *tmp;
3875*5552b385SBrandon 
3876*5552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_edgeObj, &tmp));
3877*5552b385SBrandon       PetscCall(PetscFree(tmp));
3878*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_edgeObj, cp_edge));
3879*5552b385SBrandon     }
3880*5552b385SBrandon 
3881*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject *)&w_edgeObj));
3882*5552b385SBrandon     if (!w_edgeObj) {
3883*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_edgeObj));
3884*5552b385SBrandon       PetscCall(PetscContainerSetPointer(w_edgeObj, w_edge));
3885*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_edgeObj, PetscCtxDestroyDefault));
3886*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject)w_edgeObj));
3887*5552b385SBrandon       PetscCall(PetscContainerDestroy(&w_edgeObj));
3888*5552b385SBrandon     } else {
3889*5552b385SBrandon       void *tmp;
3890*5552b385SBrandon 
3891*5552b385SBrandon       PetscCall(PetscContainerGetPointer(w_edgeObj, &tmp));
3892*5552b385SBrandon       PetscCall(PetscFree(tmp));
3893*5552b385SBrandon       PetscCall(PetscContainerSetPointer(w_edgeObj, w_edge));
3894*5552b385SBrandon     }
3895*5552b385SBrandon 
3896*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Vertex Map", (PetscObject *)&cp_vertexObj));
3897*5552b385SBrandon     if (!cp_vertexObj) {
3898*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_vertexObj));
3899*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_vertexObj, cp_vertex));
3900*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_vertexObj, PetscCtxDestroyDefault));
3901*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Vertex Map", (PetscObject)cp_vertexObj));
3902*5552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_vertexObj));
3903*5552b385SBrandon     } else {
3904*5552b385SBrandon       void *tmp;
3905*5552b385SBrandon 
3906*5552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_vertexObj, &tmp));
3907*5552b385SBrandon       PetscCall(PetscFree(tmp));
3908*5552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_vertexObj, cp_vertex));
3909*5552b385SBrandon     }
3910*5552b385SBrandon 
3911*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject *)&w_vertexObj));
3912*5552b385SBrandon     if (!w_vertexObj) {
3913*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_vertexObj));
3914*5552b385SBrandon       PetscCall(PetscContainerSetPointer(w_vertexObj, w_vertex));
3915*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_vertexObj, PetscCtxDestroyDefault));
3916*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject)w_vertexObj));
3917*5552b385SBrandon       PetscCall(PetscContainerDestroy(&w_vertexObj));
3918*5552b385SBrandon     } else {
3919*5552b385SBrandon       void *tmp;
3920*5552b385SBrandon 
3921*5552b385SBrandon       PetscCall(PetscContainerGetPointer(w_vertexObj, &tmp));
3922*5552b385SBrandon       PetscCall(PetscFree(tmp));
3923*5552b385SBrandon       PetscCall(PetscContainerSetPointer(w_vertexObj, w_vertex));
3924*5552b385SBrandon     }
3925*5552b385SBrandon   }
3926*5552b385SBrandon 
3927*5552b385SBrandon   // Define Matrix to store  Geometry Gradient information dGeom_i/dCPj_i
3928*5552b385SBrandon   PetscInt       gcntr   = 0;
3929*5552b385SBrandon   const PetscInt rowSize = 3 * maxNumCPs * totalNumPoints;
3930*5552b385SBrandon   const PetscInt colSize = 4 * Nf;
3931*5552b385SBrandon 
3932*5552b385SBrandon   // Create Point Surface Gradient Matrix
3933*5552b385SBrandon   PetscCall(MatCreate(PETSC_COMM_WORLD, &pointSurfGrad));
3934*5552b385SBrandon   PetscCall(MatSetSizes(pointSurfGrad, PETSC_DECIDE, PETSC_DECIDE, rowSize, colSize));
3935*5552b385SBrandon   PetscCall(MatSetType(pointSurfGrad, MATAIJ));
3936*5552b385SBrandon   PetscCall(MatSetUp(pointSurfGrad));
3937*5552b385SBrandon 
3938*5552b385SBrandon   // Create Hash Table to store Point's stare row in surfaceGrad[][]
3939*5552b385SBrandon   PetscCall(PetscHMapICreate(&pointSurfGradRow_Start));
3940*5552b385SBrandon 
3941*5552b385SBrandon   // Get Coordinates for the DMPlex point
3942*5552b385SBrandon   DM           cdm;
3943*5552b385SBrandon   PetscInt     dE, Nv;
3944*5552b385SBrandon   Vec          coordinatesLocal;
3945*5552b385SBrandon   PetscScalar *coords = NULL;
3946*5552b385SBrandon 
3947*5552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
3948*5552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &dE));
3949*5552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
3950*5552b385SBrandon 
3951*5552b385SBrandon   // CYCLE THROUGH FACEs
3952*5552b385SBrandon   PetscScalar maxGrad = 0.;
3953*5552b385SBrandon   PetscCall(VecGetArrayWrite(gradSACPVec, &gradSACP));
3954*5552b385SBrandon   PetscCall(VecGetArrayWrite(gradSAWVec, &gradSAW));
3955*5552b385SBrandon   PetscCall(VecGetArrayWrite(gradVCPVec, &gradVCP));
3956*5552b385SBrandon   PetscCall(VecGetArrayWrite(gradVWVec, &gradVW));
3957*5552b385SBrandon   for (int f = 0; f < Nf; ++f) {
3958*5552b385SBrandon     ego             face = fobjs[f];
3959*5552b385SBrandon     ego            *eobjs, *nobjs;
3960*5552b385SBrandon     PetscInt        fid, Ne, Nn;
3961*5552b385SBrandon     DMLabel         faceLabel, edgeLabel, nodeLabel;
3962*5552b385SBrandon     PetscHMapI      currFaceUniquePoints = NULL;
3963*5552b385SBrandon     IS              facePoints, edgePoints, nodePoints;
3964*5552b385SBrandon     const PetscInt *fIndices, *eIndices, *nIndices;
3965*5552b385SBrandon     PetscInt        fSize, eSize, nSize;
3966*5552b385SBrandon     PetscHashIter   fHashKeyIter, eHashKeyIter, nHashKeyIter, pHashKeyIter;
3967*5552b385SBrandon     PetscBool       fHashKeyFound, eHashKeyFound, nHashKeyFound, pHashKeyFound;
3968*5552b385SBrandon     PetscInt        cfCntr = 0;
3969*5552b385SBrandon 
3970*5552b385SBrandon     // Get Geometry Object for the Current FACE
3971*5552b385SBrandon     if (islite) {
3972*5552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3973*5552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3974*5552b385SBrandon     } else {
3975*5552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
3976*5552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
3977*5552b385SBrandon     }
3978*5552b385SBrandon 
3979*5552b385SBrandon     // Get all EDGE and NODE objects attached to the current FACE
3980*5552b385SBrandon     if (islite) {
3981*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
3982*5552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, NODE, &Nn, &nobjs));
3983*5552b385SBrandon     } else {
3984*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
3985*5552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, NODE, &Nn, &nobjs));
3986*5552b385SBrandon     }
3987*5552b385SBrandon 
3988*5552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Face ID" and store them in a Hash Table for later use
3989*5552b385SBrandon     if (islite) {
3990*5552b385SBrandon       fid = EGlite_indexBodyTopo(body, face);
3991*5552b385SBrandon     } else {
3992*5552b385SBrandon       fid = EG_indexBodyTopo(body, face);
3993*5552b385SBrandon     }
3994*5552b385SBrandon 
3995*5552b385SBrandon     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
3996*5552b385SBrandon     PetscCall(DMLabelGetStratumIS(faceLabel, fid, &facePoints));
3997*5552b385SBrandon     PetscCall(ISGetIndices(facePoints, &fIndices));
3998*5552b385SBrandon     PetscCall(ISGetSize(facePoints, &fSize));
3999*5552b385SBrandon 
4000*5552b385SBrandon     PetscCall(PetscHMapICreate(&currFaceUniquePoints));
4001*5552b385SBrandon 
4002*5552b385SBrandon     for (int jj = 0; jj < fSize; ++jj) {
4003*5552b385SBrandon       PetscCall(PetscHMapIFind(currFaceUniquePoints, fIndices[jj], &fHashKeyIter, &fHashKeyFound));
4004*5552b385SBrandon 
4005*5552b385SBrandon       if (!fHashKeyFound) {
4006*5552b385SBrandon         PetscCall(PetscHMapISet(currFaceUniquePoints, fIndices[jj], cfCntr));
4007*5552b385SBrandon         cfCntr += 1;
4008*5552b385SBrandon       }
4009*5552b385SBrandon 
4010*5552b385SBrandon       PetscCall(PetscHMapIFind(pointSurfGradRow_Start, fIndices[jj], &pHashKeyIter, &pHashKeyFound));
4011*5552b385SBrandon 
4012*5552b385SBrandon       if (!pHashKeyFound) {
4013*5552b385SBrandon         PetscCall(PetscHMapISet(pointSurfGradRow_Start, fIndices[jj], gcntr));
4014*5552b385SBrandon         gcntr += 3 * maxNumCPs;
4015*5552b385SBrandon       }
4016*5552b385SBrandon     }
4017*5552b385SBrandon     PetscCall(ISRestoreIndices(facePoints, &fIndices));
4018*5552b385SBrandon     PetscCall(ISDestroy(&facePoints));
4019*5552b385SBrandon 
4020*5552b385SBrandon     // 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.
4021*5552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
4022*5552b385SBrandon       ego       edge = eobjs[jj];
4023*5552b385SBrandon       PetscBool containLabelValue;
4024*5552b385SBrandon 
4025*5552b385SBrandon       if (islite) {
4026*5552b385SBrandon         id = EGlite_indexBodyTopo(body, edge);
4027*5552b385SBrandon       } else {
4028*5552b385SBrandon         id = EG_indexBodyTopo(body, edge);
4029*5552b385SBrandon       }
4030*5552b385SBrandon 
4031*5552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
4032*5552b385SBrandon       PetscCall(DMLabelHasValue(edgeLabel, id, &containLabelValue));
4033*5552b385SBrandon 
4034*5552b385SBrandon       if (containLabelValue) {
4035*5552b385SBrandon         PetscCall(DMLabelGetStratumIS(edgeLabel, id, &edgePoints));
4036*5552b385SBrandon         PetscCall(ISGetIndices(edgePoints, &eIndices));
4037*5552b385SBrandon         PetscCall(ISGetSize(edgePoints, &eSize));
4038*5552b385SBrandon 
4039*5552b385SBrandon         for (int kk = 0; kk < eSize; ++kk) {
4040*5552b385SBrandon           PetscCall(PetscHMapIFind(currFaceUniquePoints, eIndices[kk], &eHashKeyIter, &eHashKeyFound));
4041*5552b385SBrandon 
4042*5552b385SBrandon           if (!eHashKeyFound) {
4043*5552b385SBrandon             PetscCall(PetscHMapISet(currFaceUniquePoints, eIndices[kk], cfCntr));
4044*5552b385SBrandon             cfCntr += 1;
4045*5552b385SBrandon           }
4046*5552b385SBrandon 
4047*5552b385SBrandon           PetscCall(PetscHMapIFind(pointSurfGradRow_Start, eIndices[kk], &pHashKeyIter, &pHashKeyFound));
4048*5552b385SBrandon 
4049*5552b385SBrandon           if (!pHashKeyFound) {
4050*5552b385SBrandon             PetscCall(PetscHMapISet(pointSurfGradRow_Start, eIndices[kk], gcntr));
4051*5552b385SBrandon             gcntr += 3 * maxNumCPs;
4052*5552b385SBrandon           }
4053*5552b385SBrandon         }
4054*5552b385SBrandon         PetscCall(ISRestoreIndices(edgePoints, &eIndices));
4055*5552b385SBrandon         PetscCall(ISDestroy(&edgePoints));
4056*5552b385SBrandon       }
4057*5552b385SBrandon     }
4058*5552b385SBrandon 
4059*5552b385SBrandon     // 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.
4060*5552b385SBrandon     for (int jj = 0; jj < Nn; ++jj) {
4061*5552b385SBrandon       ego node = nobjs[jj];
4062*5552b385SBrandon 
4063*5552b385SBrandon       if (islite) {
4064*5552b385SBrandon         id = EGlite_indexBodyTopo(body, node);
4065*5552b385SBrandon       } else {
4066*5552b385SBrandon         id = EG_indexBodyTopo(body, node);
4067*5552b385SBrandon       }
4068*5552b385SBrandon 
4069*5552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &nodeLabel));
4070*5552b385SBrandon       PetscCall(DMLabelGetStratumIS(nodeLabel, id, &nodePoints));
4071*5552b385SBrandon       PetscCall(ISGetIndices(nodePoints, &nIndices));
4072*5552b385SBrandon       PetscCall(ISGetSize(nodePoints, &nSize));
4073*5552b385SBrandon 
4074*5552b385SBrandon       for (int kk = 0; kk < nSize; ++kk) {
4075*5552b385SBrandon         PetscCall(PetscHMapIFind(currFaceUniquePoints, nIndices[kk], &nHashKeyIter, &nHashKeyFound));
4076*5552b385SBrandon 
4077*5552b385SBrandon         if (!nHashKeyFound) {
4078*5552b385SBrandon           PetscCall(PetscHMapISet(currFaceUniquePoints, nIndices[kk], cfCntr));
4079*5552b385SBrandon           cfCntr += 1;
4080*5552b385SBrandon         }
4081*5552b385SBrandon 
4082*5552b385SBrandon         PetscCall(PetscHMapIFind(pointSurfGradRow_Start, nIndices[kk], &pHashKeyIter, &pHashKeyFound));
4083*5552b385SBrandon         if (!pHashKeyFound) {
4084*5552b385SBrandon           PetscCall(PetscHMapISet(pointSurfGradRow_Start, nIndices[kk], gcntr));
4085*5552b385SBrandon           gcntr += 3 * maxNumCPs;
4086*5552b385SBrandon         }
4087*5552b385SBrandon       }
4088*5552b385SBrandon       PetscCall(ISRestoreIndices(nodePoints, &nIndices));
4089*5552b385SBrandon       PetscCall(ISDestroy(&nodePoints));
4090*5552b385SBrandon     }
4091*5552b385SBrandon 
4092*5552b385SBrandon     // Get the Total Number of entries in the Hash Table
4093*5552b385SBrandon     PetscInt currFaceUPSize;
4094*5552b385SBrandon     PetscCall(PetscHMapIGetSize(currFaceUniquePoints, &currFaceUPSize));
4095*5552b385SBrandon 
4096*5552b385SBrandon     // Get Keys
4097*5552b385SBrandon     PetscInt currFaceUPKeys[currFaceUPSize], off = 0;
4098*5552b385SBrandon     PetscCall(PetscHMapIGetKeys(currFaceUniquePoints, &off, currFaceUPKeys));
4099*5552b385SBrandon     PetscCall(PetscHMapIDestroy(&currFaceUniquePoints));
4100*5552b385SBrandon 
4101*5552b385SBrandon     // Get Current Face Surface Area
4102*5552b385SBrandon     PetscScalar fSA, faceData[14];
4103*5552b385SBrandon     PetscCall(EG_getMassProperties(face, faceData)); // This doesn't have a EGlite version. Will it work for EGADSlite files??  KNOWN_ISSUE
4104*5552b385SBrandon     fSA = faceData[1];
4105*5552b385SBrandon 
4106*5552b385SBrandon     // Get Start Row in cpEquiv Matrix
4107*5552b385SBrandon     PetscHashIter Witer;
4108*5552b385SBrandon     PetscBool     Wfound;
4109*5552b385SBrandon     PetscInt      faceWStartRow;
4110*5552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, fid, &Witer, &Wfound));
4111*5552b385SBrandon     PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
4112*5552b385SBrandon     PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, fid, &faceWStartRow));
4113*5552b385SBrandon 
4114*5552b385SBrandon     // Cycle through all points on the current FACE
4115*5552b385SBrandon     for (int jj = 0; jj < currFaceUPSize; ++jj) {
4116*5552b385SBrandon       PetscInt currPointID = currFaceUPKeys[jj];
4117*5552b385SBrandon       PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
4118*5552b385SBrandon 
4119*5552b385SBrandon       // Get UV position of FACE
4120*5552b385SBrandon       double params[2], range[4], eval[18];
4121*5552b385SBrandon       int    peri;
4122*5552b385SBrandon 
4123*5552b385SBrandon       if (islite) PetscCall(EGlite_getRange(face, range, &peri));
4124*5552b385SBrandon       else PetscCall(EG_getRange(face, range, &peri));
4125*5552b385SBrandon 
4126*5552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
4127*5552b385SBrandon 
4128*5552b385SBrandon       if (islite) PetscCall(EGlite_evaluate(face, params, eval));
4129*5552b385SBrandon       else PetscCall(EG_evaluate(face, params, eval));
4130*5552b385SBrandon 
4131*5552b385SBrandon       // Make a new SURFACE Geometry by changing the location of the Control Points
4132*5552b385SBrandon       int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
4133*5552b385SBrandon       double nbprv[prvSize];
4134*5552b385SBrandon 
4135*5552b385SBrandon       // Cycle through each Control Point
4136*5552b385SBrandon       double denomNew, denomOld;
4137*5552b385SBrandon       double deltaCoord = 1.0E-4;
4138*5552b385SBrandon       int    offset     = bpinfo[3] + bpinfo[6];
4139*5552b385SBrandon       int    wOffset    = offset + (3 * bpinfo[2] * bpinfo[5]);
4140*5552b385SBrandon       for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) {
4141*5552b385SBrandon         PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d", f, jj, ii);
4142*5552b385SBrandon   #if 0
4143*5552b385SBrandon         // Cycle through each direction (x, then y, then z)
4144*5552b385SBrandon         if (jj == 0) {
4145*5552b385SBrandon           // Get the Number Control Points that are the same as the current points
4146*5552b385SBrandon           //    We are looking for repeated Control Points
4147*5552b385SBrandon           PetscInt commonCPcntr = 0;
4148*5552b385SBrandon           for (int mm = 0; mm < bpinfo[2]*bpinfo[5]; ++mm) {
4149*5552b385SBrandon             PetscScalar matValue;
4150*5552b385SBrandon             PetscCall(MatGetValue(cpEquiv, faceWStartRow + ii, faceWStartRow + mm, &matValue));
4151*5552b385SBrandon 
4152*5552b385SBrandon             if (matValue > 0.0) commonCPcntr += 1;
4153*5552b385SBrandon           }
4154*5552b385SBrandon         }
4155*5552b385SBrandon   #endif
4156*5552b385SBrandon 
4157*5552b385SBrandon         for (int kk = 0; kk < 4; ++kk) {
4158*5552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
4159*5552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) { nbprv[mm] = bprv[mm]; }
4160*5552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
4161*5552b385SBrandon 
4162*5552b385SBrandon           if (kk == 0) { //X
4163*5552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0] + deltaCoord;
4164*5552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
4165*5552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
4166*5552b385SBrandon             denomNew          = nbprv[offset + 0];
4167*5552b385SBrandon             denomOld          = bprv[offset + 0];
4168*5552b385SBrandon           } else if (kk == 1) { //Y
4169*5552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
4170*5552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1] + deltaCoord;
4171*5552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
4172*5552b385SBrandon             denomNew          = nbprv[offset + 1];
4173*5552b385SBrandon             denomOld          = bprv[offset + 1];
4174*5552b385SBrandon           } else if (kk == 2) { //Z
4175*5552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
4176*5552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
4177*5552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2] + deltaCoord;
4178*5552b385SBrandon             denomNew          = nbprv[offset + 2];
4179*5552b385SBrandon             denomOld          = bprv[offset + 2];
4180*5552b385SBrandon           } else if (kk == 3) { // Weights
4181*5552b385SBrandon             nbprv[wOffset + ii] = bprv[wOffset + ii] + deltaCoord;
4182*5552b385SBrandon             denomNew            = nbprv[wOffset + ii];
4183*5552b385SBrandon             denomOld            = bprv[wOffset + ii];
4184*5552b385SBrandon           } else {
4185*5552b385SBrandon             // currently do nothing
4186*5552b385SBrandon           }
4187*5552b385SBrandon 
4188*5552b385SBrandon           // Create New Surface Based on New Control Points or Weights
4189*5552b385SBrandon           ego newgeom, context;
4190*5552b385SBrandon           PetscCallEGADS(EG_getContext, (face, &context));                                             // This does not have an EGlite_ version KNOWN_ISSUE
4191*5552b385SBrandon           PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // This does not have an EGlite_ version KNOWN_ISSUE
4192*5552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
4193*5552b385SBrandon 
4194*5552b385SBrandon           // Evaluate new (x, y, z) Point Position based on new Surface Definition
4195*5552b385SBrandon           double newCoords[18];
4196*5552b385SBrandon           if (islite) PetscCall(EGlite_getRange(newgeom, range, &peri));
4197*5552b385SBrandon           else PetscCall(EG_getRange(newgeom, range, &peri));
4198*5552b385SBrandon 
4199*5552b385SBrandon           PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
4200*5552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
4201*5552b385SBrandon 
4202*5552b385SBrandon           if (islite) PetscCall(EGlite_evaluate(newgeom, params, newCoords));
4203*5552b385SBrandon           else PetscCall(EG_evaluate(newgeom, params, newCoords));
4204*5552b385SBrandon 
4205*5552b385SBrandon           // Calculate Surface Area Gradients wrt Control Points and Weights using the local discrete FACE only
4206*5552b385SBrandon           //      NOTE 1: Will not provide Volume Gradient wrt to Control Points and Weights.
4207*5552b385SBrandon           //      NOTE 2: This is faster than below where an entire new solid geometry is created for each
4208*5552b385SBrandon           //              Control Point and Weight gradient
4209*5552b385SBrandon           if (!fullGeomGrad) {
4210*5552b385SBrandon             // Create new FACE based on new SURFACE geometry
4211*5552b385SBrandon             if (jj == 0) { // only for 1st DMPlex Point because we only per CP or Weight
4212*5552b385SBrandon               double newFaceRange[4];
4213*5552b385SBrandon               int    newFacePeri;
4214*5552b385SBrandon               if (islite) PetscCall(EGlite_getRange(newgeom, newFaceRange, &newFacePeri));
4215*5552b385SBrandon               else PetscCall(EG_getRange(newgeom, newFaceRange, &newFacePeri));
4216*5552b385SBrandon 
4217*5552b385SBrandon               ego newface;
4218*5552b385SBrandon               PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, newFaceRange, &newface)); // Does not have EGlite version KNOWN_ISSUE
4219*5552b385SBrandon               PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
4220*5552b385SBrandon 
4221*5552b385SBrandon               // Get New Face Surface Area
4222*5552b385SBrandon               PetscScalar newfSA, newFaceData[14];
4223*5552b385SBrandon               PetscCall(EG_getMassProperties(newface, newFaceData)); // Does not have EGlite version KNOWN_ISSUE
4224*5552b385SBrandon               newfSA = newFaceData[1];
4225*5552b385SBrandon               PetscCallEGADS(EG_deleteObject, (newface));
4226*5552b385SBrandon               PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
4227*5552b385SBrandon 
4228*5552b385SBrandon               // Update Control Points
4229*5552b385SBrandon               PetscHashIter CPiter, Witer;
4230*5552b385SBrandon               PetscBool     CPfound, Wfound;
4231*5552b385SBrandon               PetscInt      faceCPStartRow, faceWStartRow;
4232*5552b385SBrandon 
4233*5552b385SBrandon               PetscScalar dSAdCPi;
4234*5552b385SBrandon               dSAdCPi = (newfSA - fSA) / (denomNew - denomOld);
4235*5552b385SBrandon 
4236*5552b385SBrandon               if (kk < 3) {
4237*5552b385SBrandon                 PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, fid, &CPiter, &CPfound));
4238*5552b385SBrandon                 PetscCheck(CPfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
4239*5552b385SBrandon                 PetscCall(PetscHMapIGet(faceCntrlPtRow_Start, fid, &faceCPStartRow));
4240*5552b385SBrandon 
4241*5552b385SBrandon                 gradSACP[faceCPStartRow + (ii * 3) + kk] = dSAdCPi;
4242*5552b385SBrandon 
4243*5552b385SBrandon                 if (PetscAbsReal(dSAdCPi) > maxGrad) maxGrad = PetscAbsReal(dSAdCPi);
4244*5552b385SBrandon 
4245*5552b385SBrandon               } else if (kk == 3) {
4246*5552b385SBrandon                 PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, fid, &Witer, &Wfound));
4247*5552b385SBrandon                 PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
4248*5552b385SBrandon                 PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, fid, &faceWStartRow));
4249*5552b385SBrandon 
4250*5552b385SBrandon                 gradSAW[faceWStartRow + ii] = dSAdCPi;
4251*5552b385SBrandon 
4252*5552b385SBrandon               } else {
4253*5552b385SBrandon                 // Do Nothing
4254*5552b385SBrandon               }
4255*5552b385SBrandon             }
4256*5552b385SBrandon           }
4257*5552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newgeom));
4258*5552b385SBrandon 
4259*5552b385SBrandon           // Now Calculate the Surface Gradient for the change in x-component Control Point
4260*5552b385SBrandon           PetscScalar dxdCx = (newCoords[0] - coords[0]) / deltaCoord;
4261*5552b385SBrandon           PetscScalar dxdCy = (newCoords[1] - coords[1]) / deltaCoord;
4262*5552b385SBrandon           PetscScalar dxdCz = (newCoords[2] - coords[2]) / deltaCoord;
4263*5552b385SBrandon 
4264*5552b385SBrandon           // Store Gradient Information in surfaceGrad[][] Matrix
4265*5552b385SBrandon           PetscInt startRow;
4266*5552b385SBrandon           PetscCall(PetscHMapIGet(pointSurfGradRow_Start, currPointID, &startRow));
4267*5552b385SBrandon 
4268*5552b385SBrandon           // Store Results in Petsc Matrix
4269*5552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 0, ((fid - 1) * 4) + kk, dxdCx, INSERT_VALUES));
4270*5552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 1, ((fid - 1) * 4) + kk, dxdCy, INSERT_VALUES));
4271*5552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 2, ((fid - 1) * 4) + kk, dxdCz, INSERT_VALUES));
4272*5552b385SBrandon 
4273*5552b385SBrandon           //PetscCallEGADS(EG_deleteObject, (newgeom));
4274*5552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face is corrupted");
4275*5552b385SBrandon         }
4276*5552b385SBrandon         offset += 3;
4277*5552b385SBrandon       }
4278*5552b385SBrandon       PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
4279*5552b385SBrandon     }
4280*5552b385SBrandon   }
4281*5552b385SBrandon 
4282*5552b385SBrandon   // Assemble Point Surface Grad Matrix
4283*5552b385SBrandon   PetscCall(MatAssemblyBegin(pointSurfGrad, MAT_FINAL_ASSEMBLY));
4284*5552b385SBrandon   PetscCall(MatAssemblyEnd(pointSurfGrad, MAT_FINAL_ASSEMBLY));
4285*5552b385SBrandon 
4286*5552b385SBrandon   if (fullGeomGrad) {
4287*5552b385SBrandon     // Calculate Surface Area and Volume Control Point and Control Point Weight Gradients
4288*5552b385SBrandon     //    Note: This is much slower than above due to a new solid geometry being created for
4289*5552b385SBrandon     //          each change in Control Point and Control Point Weight. However, this method
4290*5552b385SBrandon     //          will provide the Volume Gradient.
4291*5552b385SBrandon 
4292*5552b385SBrandon     // Get Current Face Surface Area
4293*5552b385SBrandon     PetscScalar bodyVol, bodySA, bodyData[14];
4294*5552b385SBrandon     PetscCall(EG_getMassProperties(body, bodyData)); // Does not have an EGlite versin KNOWN_ISSUE
4295*5552b385SBrandon     bodyVol = bodyData[0];
4296*5552b385SBrandon     bodySA  = bodyData[1];
4297*5552b385SBrandon 
4298*5552b385SBrandon     // Cycle through Control Points
4299*5552b385SBrandon     for (int ii = 0; ii < totalNumCPs; ++ii) { // ii should also be the row in cpEquiv for the Control Point
4300*5552b385SBrandon       // Cycle through X, Y, Z, W changes
4301*5552b385SBrandon       for (int jj = 0; jj < 4; ++jj) {
4302*5552b385SBrandon         // Cycle Through Faces
4303*5552b385SBrandon         double denomNew = 0.0, denomOld = 0.0;
4304*5552b385SBrandon         double deltaCoord = 1.0E-4;
4305*5552b385SBrandon         ego    newGeom[Nf];
4306*5552b385SBrandon         ego    newFaces[Nf];
4307*5552b385SBrandon         for (int kk = 0; kk < Nf; ++kk) {
4308*5552b385SBrandon           ego      face;
4309*5552b385SBrandon           PetscInt currFID = kk + 1;
4310*5552b385SBrandon 
4311*5552b385SBrandon           if (islite) {
4312*5552b385SBrandon             // Get Current FACE
4313*5552b385SBrandon             PetscCallEGADS(EGlite_objectBodyTopo, (body, FACE, currFID, &face));
4314*5552b385SBrandon 
4315*5552b385SBrandon             // Get Geometry Object for the Current FACE
4316*5552b385SBrandon             PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
4317*5552b385SBrandon             PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
4318*5552b385SBrandon           } else {
4319*5552b385SBrandon             // Get Current FACE
4320*5552b385SBrandon             PetscCallEGADS(EG_objectBodyTopo, (body, FACE, currFID, &face));
4321*5552b385SBrandon 
4322*5552b385SBrandon             // Get Geometry Object for the Current FACE
4323*5552b385SBrandon             PetscCallEGADS(EG_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
4324*5552b385SBrandon             PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
4325*5552b385SBrandon           }
4326*5552b385SBrandon 
4327*5552b385SBrandon           // Make a new SURFACE Geometry by changing the location of the Control Points
4328*5552b385SBrandon           int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
4329*5552b385SBrandon           double nbprv[prvSize];
4330*5552b385SBrandon 
4331*5552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
4332*5552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) nbprv[mm] = bprv[mm];
4333*5552b385SBrandon 
4334*5552b385SBrandon           // Get Control Point Row and Column Start for cpEquiv
4335*5552b385SBrandon           PetscHashIter Witer;
4336*5552b385SBrandon           PetscBool     Wfound;
4337*5552b385SBrandon           PetscInt      faceWStartRow;
4338*5552b385SBrandon           PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, currFID, &Witer, &Wfound));
4339*5552b385SBrandon           PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
4340*5552b385SBrandon           PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, currFID, &faceWStartRow));
4341*5552b385SBrandon 
4342*5552b385SBrandon           // Modify the Current Control Point on this FACE and All Other FACES
4343*5552b385SBrandon           // IMPORTANT!!! If you do not move all identical Control Points on other FACES
4344*5552b385SBrandon           //              you will not generate a solid body. You will generate a set of
4345*5552b385SBrandon           //              disconnected surfaces that have gap(s) between them.
4346*5552b385SBrandon           int offset  = bpinfo[3] + bpinfo[6];
4347*5552b385SBrandon           int wOffset = offset + (3 * bpinfo[2] * bpinfo[5]);
4348*5552b385SBrandon           for (int mm = 0; mm < bpinfo[2] * bpinfo[5]; ++mm) {
4349*5552b385SBrandon             PetscScalar matValue;
4350*5552b385SBrandon             PetscCall(MatGetValue(cpEquiv, ii, faceWStartRow + mm, &matValue));
4351*5552b385SBrandon 
4352*5552b385SBrandon             if (matValue > 0.0) {
4353*5552b385SBrandon               if (jj == 0) { //X
4354*5552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0] + deltaCoord;
4355*5552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1];
4356*5552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2];
4357*5552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 0];
4358*5552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 0];
4359*5552b385SBrandon               } else if (jj == 1) { //Y
4360*5552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0];
4361*5552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1] + deltaCoord;
4362*5552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2];
4363*5552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 1];
4364*5552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 1];
4365*5552b385SBrandon               } else if (jj == 2) { //Z
4366*5552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0];
4367*5552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1];
4368*5552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2] + deltaCoord;
4369*5552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 2];
4370*5552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 2];
4371*5552b385SBrandon               } else if (jj == 3) { // Weights
4372*5552b385SBrandon                 nbprv[wOffset + mm] = bprv[wOffset + mm] + deltaCoord;
4373*5552b385SBrandon                 denomNew            = nbprv[wOffset + mm];
4374*5552b385SBrandon                 denomOld            = bprv[wOffset + mm];
4375*5552b385SBrandon               } else {
4376*5552b385SBrandon                 // currently do nothing
4377*5552b385SBrandon               }
4378*5552b385SBrandon             }
4379*5552b385SBrandon           }
4380*5552b385SBrandon 
4381*5552b385SBrandon           // Create New Surface Based on New Control Points or Weights
4382*5552b385SBrandon           ego newgeom, context;
4383*5552b385SBrandon           PetscCallEGADS(EG_getContext, (face, &context));                                             // Does not have an EGlite_ versions   KNOWN_ISSUE
4384*5552b385SBrandon           PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
4385*5552b385SBrandon 
4386*5552b385SBrandon           // Create New FACE based on modified geometry
4387*5552b385SBrandon           double newFaceRange[4];
4388*5552b385SBrandon           int    newFacePeri;
4389*5552b385SBrandon           if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, newFaceRange, &newFacePeri));
4390*5552b385SBrandon           else PetscCallEGADS(EG_getRange, (newgeom, newFaceRange, &newFacePeri));
4391*5552b385SBrandon 
4392*5552b385SBrandon           ego newface;
4393*5552b385SBrandon           PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, newFaceRange, &newface)); // Does not have an EGlite_ version KNOWN_ISSUE
4394*5552b385SBrandon 
4395*5552b385SBrandon           // store new face for later assembly
4396*5552b385SBrandon           newGeom[kk]  = newgeom;
4397*5552b385SBrandon           newFaces[kk] = newface;
4398*5552b385SBrandon         }
4399*5552b385SBrandon 
4400*5552b385SBrandon         // X-WANT TO BUILD THE NEW GEOMETRY, X-GET NEW SA AND PERFORM dSA/dCPi CALCS HERE <---
4401*5552b385SBrandon         // Sew New Faces together to get a new model
4402*5552b385SBrandon         ego newmodel;
4403*5552b385SBrandon         PetscCall(EG_sewFaces(Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version KNOWN_ISSUE
4404*5552b385SBrandon 
4405*5552b385SBrandon         // Get Surface Area and Volume of New/Updated Solid Body
4406*5552b385SBrandon         PetscScalar newData[14];
4407*5552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getTopology, (newmodel, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
4408*5552b385SBrandon         else PetscCallEGADS(EG_getTopology, (newmodel, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
4409*5552b385SBrandon 
4410*5552b385SBrandon         ego nbody = bodies[0];
4411*5552b385SBrandon         PetscCall(EG_getMassProperties(nbody, newData)); // Does not have an EGlite_ version   KNOWN_ISSUE
4412*5552b385SBrandon 
4413*5552b385SBrandon         PetscScalar dSAdCPi, dVdCPi;
4414*5552b385SBrandon         PetscScalar nbodyVol = newData[0], nbodySA = newData[1];
4415*5552b385SBrandon 
4416*5552b385SBrandon         // Calculate Gradients wrt to Control Points and Control Points Weights depending on jj value
4417*5552b385SBrandon         dSAdCPi = (nbodySA - bodySA) / (denomNew - denomOld);
4418*5552b385SBrandon         dVdCPi  = (nbodyVol - bodyVol) / (denomNew - denomOld);
4419*5552b385SBrandon 
4420*5552b385SBrandon         if (jj < 3) {
4421*5552b385SBrandon           // Gradienst wrt to Control Points
4422*5552b385SBrandon           gradSACP[(ii * 3) + jj] = dSAdCPi;
4423*5552b385SBrandon           gradVCP[(ii * 3) + jj]  = dVdCPi;
4424*5552b385SBrandon         } else if (jj == 3) {
4425*5552b385SBrandon           // Gradients wrt to Control Point Weights
4426*5552b385SBrandon           gradSAW[ii] = dSAdCPi;
4427*5552b385SBrandon           gradVW[ii]  = dVdCPi;
4428*5552b385SBrandon         } else {
4429*5552b385SBrandon           // Do Nothing
4430*5552b385SBrandon         }
4431*5552b385SBrandon         PetscCallEGADS(EG_deleteObject, (newmodel));
4432*5552b385SBrandon         for (int kk = 0; kk < Nf; ++kk) {
4433*5552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newFaces[kk]));
4434*5552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newGeom[kk]));
4435*5552b385SBrandon         }
4436*5552b385SBrandon       }
4437*5552b385SBrandon     }
4438*5552b385SBrandon   }
4439*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradSACPVec, &gradSACP));
4440*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradSAWVec, &gradSAW));
4441*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradVCPVec, &gradVCP));
4442*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradVWVec, &gradVW));
4443*5552b385SBrandon   PetscCall(MatDestroy(&cpEquiv));
4444*5552b385SBrandon 
4445*5552b385SBrandon   // Attach Surface Gradient Hash Table and Matrix to DM
4446*5552b385SBrandon   {
4447*5552b385SBrandon     PetscContainer surfGradOrgObj;
4448*5552b385SBrandon 
4449*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject *)&surfGradOrgObj));
4450*5552b385SBrandon     if (!surfGradOrgObj) {
4451*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradOrgObj));
4452*5552b385SBrandon       PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
4453*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(surfGradOrgObj, DestroyHashMap));
4454*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject)surfGradOrgObj));
4455*5552b385SBrandon       PetscCall(PetscContainerDestroy(&surfGradOrgObj));
4456*5552b385SBrandon     } else {
4457*5552b385SBrandon       PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
4458*5552b385SBrandon     }
4459*5552b385SBrandon 
4460*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Matrix", (PetscObject)pointSurfGrad));
4461*5552b385SBrandon     PetscCall(MatDestroy(&pointSurfGrad));
4462*5552b385SBrandon 
4463*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject)gradSACPVec));
4464*5552b385SBrandon     PetscCall(VecDestroy(&gradSACPVec));
4465*5552b385SBrandon 
4466*5552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject)gradSAWVec));
4467*5552b385SBrandon     PetscCall(VecDestroy(&gradSAWVec));
4468*5552b385SBrandon 
4469*5552b385SBrandon     if (fullGeomGrad) {
4470*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Volume Control Point Gradient", (PetscObject)gradVCPVec));
4471*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Volume Weights Gradient", (PetscObject)gradVWVec));
4472*5552b385SBrandon     }
4473*5552b385SBrandon     PetscCall(VecDestroy(&gradVCPVec));
4474*5552b385SBrandon     PetscCall(VecDestroy(&gradVWVec));
4475*5552b385SBrandon   }
4476*5552b385SBrandon 
4477*5552b385SBrandon   // Could be replaced with DMPlexFreeGeomObject()
4478*5552b385SBrandon   if (islite) EGlite_free(fobjs);
4479*5552b385SBrandon   else EG_free(fobjs);
4480*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
4481*5552b385SBrandon #else
4482*5552b385SBrandon   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
4483*5552b385SBrandon #endif
4484*5552b385SBrandon }
4485*5552b385SBrandon 
4486*5552b385SBrandon /*@C
4487*5552b385SBrandon   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.
4488*5552b385SBrandon 
4489*5552b385SBrandon   Collective
4490*5552b385SBrandon 
4491*5552b385SBrandon   Input Parameters:
4492*5552b385SBrandon + dm          - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
4493*5552b385SBrandon . comm        - MPI_Comm object
4494*5552b385SBrandon . newCP       - C Array of [x, y, z] New/Updated Control Point Coordinates defining the geometry (See DMPlexGeomDataAndGrads() for format)
4495*5552b385SBrandon . newW        - C Array of New/Updated Control Point Weights associated with the Control Points defining the new geometry (See DMPlexGemGrads() for format)
4496*5552b385SBrandon . autoInflate - PetscBool Flag denoting if the user would like to inflate the DM points to the new geometry.
4497*5552b385SBrandon . saveGeom    - PetscBool Flag denoting if the user would iike to save the new geometry to a file.
4498*5552b385SBrandon - 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.
4499*5552b385SBrandon                       *.stp or *.step = STEP File
4500*5552b385SBrandon                       *.igs or *.iges = IGES File
4501*5552b385SBrandon                               *.egads = EGADS File
4502*5552b385SBrandon                                *.brep = BRep File (OpenCASCADE File)
4503*5552b385SBrandon 
4504*5552b385SBrandon   Output Parameter:
4505*5552b385SBrandon . dm - The updated DM object representing the mesh with PetscContainers containing the updated/modified geometry
4506*5552b385SBrandon 
4507*5552b385SBrandon   Level: intermediate
4508*5552b385SBrandon 
4509*5552b385SBrandon   Note:
4510*5552b385SBrandon   Functionality not available for DMPlexes with attached EGADSlite geometry files (.egadslite).
4511*5552b385SBrandon 
4512*5552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`
4513*5552b385SBrandon @*/
4514*5552b385SBrandon PetscErrorCode DMPlexModifyGeomModel(DM dm, MPI_Comm comm, PetscScalar newCP[], PetscScalar newW[], PetscBool autoInflate, PetscBool saveGeom, const char *stpName)
4515*5552b385SBrandon {
4516*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
4517*5552b385SBrandon   /* EGADS/EGADSlite variables */
4518*5552b385SBrandon   ego context, model, geom, *bodies, *lobjs, *fobjs;
4519*5552b385SBrandon   int oclass, mtype, *senses, *lsenses;
4520*5552b385SBrandon   int Nb, Nf, Nl, id;
4521*5552b385SBrandon   /* PETSc variables */
4522*5552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
4523*5552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj;
4524*5552b385SBrandon   PetscHMapI     cpHashTable = NULL, wHashTable = NULL;
4525*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
4526*5552b385SBrandon #endif
4527*5552b385SBrandon 
4528*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
4529*5552b385SBrandon   PetscFunctionBegin;
4530*5552b385SBrandon   // Look to see if DM has a Container with either a EGADS or EGADSlite Model
4531*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
4532*5552b385SBrandon   if (!modelObj) {
4533*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
4534*5552b385SBrandon     islite = PETSC_TRUE;
4535*5552b385SBrandon   }
4536*5552b385SBrandon   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");
4537*5552b385SBrandon   PetscCheck(modelObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "DM does not have a EGADS Geometry Model attached to it!");
4538*5552b385SBrandon 
4539*5552b385SBrandon   // Get attached EGADS model (pointer)
4540*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
4541*5552b385SBrandon 
4542*5552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
4543*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
4544*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
4545*5552b385SBrandon 
4546*5552b385SBrandon   PetscCheck(cpHashTableObj && wHashTableObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "DM does not have required Geometry Data attached! Please run DMPlexGeomDataAndGrads() Function first.");
4547*5552b385SBrandon 
4548*5552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
4549*5552b385SBrandon   PetscCall(PetscContainerGetPointer(cpHashTableObj, (void **)&cpHashTable));
4550*5552b385SBrandon   PetscCall(PetscContainerGetPointer(wHashTableObj, (void **)&wHashTable));
4551*5552b385SBrandon 
4552*5552b385SBrandon   // Get the number of bodies and body objects in the model
4553*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
4554*5552b385SBrandon   else PetscCallEGADS(EG_getTopology, (model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
4555*5552b385SBrandon 
4556*5552b385SBrandon   // Get all Faces on the body
4557*5552b385SBrandon   ego body = bodies[0];
4558*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
4559*5552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
4560*5552b385SBrandon 
4561*5552b385SBrandon   ego newGeom[Nf];
4562*5552b385SBrandon   ego newFaces[Nf];
4563*5552b385SBrandon 
4564*5552b385SBrandon   // Update Control Point and Weight definitions for each surface
4565*5552b385SBrandon   for (int jj = 0; jj < Nf; ++jj) {
4566*5552b385SBrandon     ego     face = fobjs[jj];
4567*5552b385SBrandon     ego     bRef, bPrev, bNext;
4568*5552b385SBrandon     ego     fgeom;
4569*5552b385SBrandon     int     offset;
4570*5552b385SBrandon     int     boclass, bmtype, *bpinfo;
4571*5552b385SBrandon     double *bprv;
4572*5552b385SBrandon 
4573*5552b385SBrandon     // Get FACE ID and other Geometry Data
4574*5552b385SBrandon     if (islite) {
4575*5552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
4576*5552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
4577*5552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
4578*5552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
4579*5552b385SBrandon     } else {
4580*5552b385SBrandon       id = EG_indexBodyTopo(body, face);
4581*5552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &fgeom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
4582*5552b385SBrandon       PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
4583*5552b385SBrandon       PetscCallEGADS(EG_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
4584*5552b385SBrandon     }
4585*5552b385SBrandon 
4586*5552b385SBrandon     // Update Control Points
4587*5552b385SBrandon     PetscHashIter CPiter, Witer;
4588*5552b385SBrandon     PetscBool     CPfound, Wfound;
4589*5552b385SBrandon     PetscInt      faceCPStartRow, faceWStartRow;
4590*5552b385SBrandon 
4591*5552b385SBrandon     PetscCall(PetscHMapIFind(cpHashTable, id, &CPiter, &CPfound));
4592*5552b385SBrandon     PetscCheck(CPfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
4593*5552b385SBrandon     PetscCall(PetscHMapIGet(cpHashTable, id, &faceCPStartRow));
4594*5552b385SBrandon 
4595*5552b385SBrandon     PetscCall(PetscHMapIFind(wHashTable, id, &Witer, &Wfound));
4596*5552b385SBrandon     PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
4597*5552b385SBrandon     PetscCall(PetscHMapIGet(wHashTable, id, &faceWStartRow));
4598*5552b385SBrandon 
4599*5552b385SBrandon     // UPDATE CONTROL POINTS Locations
4600*5552b385SBrandon     offset = bpinfo[3] + bpinfo[6];
4601*5552b385SBrandon     for (int ii = 0; ii < 3 * bpinfo[2] * bpinfo[5]; ++ii) { bprv[offset + ii] = newCP[faceCPStartRow + ii]; }
4602*5552b385SBrandon 
4603*5552b385SBrandon     // UPDATE CONTROL POINT WEIGHTS
4604*5552b385SBrandon     offset = bpinfo[3] + bpinfo[6] + 3 * bpinfo[2] * bpinfo[5];
4605*5552b385SBrandon     for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) { bprv[offset + ii] = newW[faceWStartRow + ii]; }
4606*5552b385SBrandon 
4607*5552b385SBrandon     // Get Context from FACE
4608*5552b385SBrandon     context = NULL;
4609*5552b385SBrandon     PetscCallEGADS(EG_getContext, (face, &context)); // Does not have an EGlite_ version  KNOWN_ISSUE
4610*5552b385SBrandon 
4611*5552b385SBrandon     // Create New Surface
4612*5552b385SBrandon     ego newgeom;
4613*5552b385SBrandon     PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, bprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
4614*5552b385SBrandon 
4615*5552b385SBrandon     // Create new FACE based on new SURFACE geometry
4616*5552b385SBrandon     double data[4];
4617*5552b385SBrandon     int    periodic;
4618*5552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, data, &periodic));
4619*5552b385SBrandon     else PetscCallEGADS(EG_getRange, (newgeom, data, &periodic));
4620*5552b385SBrandon 
4621*5552b385SBrandon     ego newface;
4622*5552b385SBrandon     PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, data, &newface)); // Does not have an EGlite_ version KNOWN_ISSUE
4623*5552b385SBrandon     newGeom[jj]  = newgeom;
4624*5552b385SBrandon     newFaces[jj] = newface;
4625*5552b385SBrandon   }
4626*5552b385SBrandon   // Could be replaced by DMPlexFreeGeomObject
4627*5552b385SBrandon   if (islite) EGlite_free(fobjs);
4628*5552b385SBrandon   else EG_free(fobjs);
4629*5552b385SBrandon 
4630*5552b385SBrandon   // Sew New Faces together to get a new model
4631*5552b385SBrandon   ego newmodel;
4632*5552b385SBrandon   PetscCall(EG_sewFaces(Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version   KNOWN_ISSUE
4633*5552b385SBrandon   for (PetscInt f = 0; f < Nf; ++f) {
4634*5552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newFaces[f]));
4635*5552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newGeom[f]));
4636*5552b385SBrandon   }
4637*5552b385SBrandon 
4638*5552b385SBrandon   // Get the total number of NODEs on the original geometry. (This will be the same for the new geometry)
4639*5552b385SBrandon   int  totalNumNode;
4640*5552b385SBrandon   ego *nobjTotal;
4641*5552b385SBrandon   if (islite) {
4642*5552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, NODE, &totalNumNode, &nobjTotal));
4643*5552b385SBrandon     EGlite_free(nobjTotal);
4644*5552b385SBrandon   } else {
4645*5552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (body, NULL, NODE, &totalNumNode, &nobjTotal));
4646*5552b385SBrandon     EG_free(nobjTotal);
4647*5552b385SBrandon   } // Could be replaced with DMPlexFreeGeomObject
4648*5552b385SBrandon 
4649*5552b385SBrandon   // Initialize vector to store equivalent NODE indices between the 2 geometries
4650*5552b385SBrandon   // FORMAT :: vector index is the Original Geometry's NODE ID, the vector Value is the New Geometry's NODE ID
4651*5552b385SBrandon   int nodeIDEquiv[totalNumNode + 1];
4652*5552b385SBrandon 
4653*5552b385SBrandon   // Now we need to Map the NODE and EDGE IDs from each Model
4654*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
4655*5552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
4656*5552b385SBrandon 
4657*5552b385SBrandon   // New CAD
4658*5552b385SBrandon   ego *newbodies, newgeomtest, *nfobjs;
4659*5552b385SBrandon   int  nNf, newNb, newoclass, newmtype, *newsenses;
4660*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (newmodel, &newgeomtest, &newoclass, &newmtype, NULL, &newNb, &newbodies, &newsenses));
4661*5552b385SBrandon   else PetscCallEGADS(EG_getTopology, (newmodel, &newgeomtest, &newoclass, &newmtype, NULL, &newNb, &newbodies, &newsenses));
4662*5552b385SBrandon 
4663*5552b385SBrandon   ego newbody = newbodies[0];
4664*5552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (newbody, NULL, FACE, &nNf, &nfobjs));
4665*5552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (newbody, NULL, FACE, &nNf, &nfobjs));
4666*5552b385SBrandon 
4667*5552b385SBrandon   PetscCheck(newNb == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ERROR :: newNb > 1 || newNb = %d", newNb);
4668*5552b385SBrandon 
4669*5552b385SBrandon   // Find Equivalent Nodes
4670*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
4671*5552b385SBrandon     double fdata[4];
4672*5552b385SBrandon     int    peri;
4673*5552b385SBrandon 
4674*5552b385SBrandon     // Get Current FACE [u, v] Ranges
4675*5552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (fobjs[ii], fdata, &peri));
4676*5552b385SBrandon     else PetscCallEGADS(EG_getRange, (fobjs[ii], fdata, &peri));
4677*5552b385SBrandon 
4678*5552b385SBrandon     // Equate NODE IDs between 2 FACEs by working through (u, v) limits of FACE
4679*5552b385SBrandon     for (int jj = 0; jj < 2; ++jj) {
4680*5552b385SBrandon       for (int kk = 2; kk < 4; ++kk) {
4681*5552b385SBrandon         double params[2] = {fdata[jj], fdata[kk]};
4682*5552b385SBrandon         double eval[18];
4683*5552b385SBrandon         if (islite) PetscCallEGADS(EGlite_evaluate, (fobjs[ii], params, eval));
4684*5552b385SBrandon         else PetscCallEGADS(EG_evaluate, (fobjs[ii], params, eval));
4685*5552b385SBrandon 
4686*5552b385SBrandon         // Original Body
4687*5552b385SBrandon         ego *nobjsOrigFace;
4688*5552b385SBrandon         int  origNn;
4689*5552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, fobjs[ii], NODE, &origNn, &nobjsOrigFace));
4690*5552b385SBrandon         else PetscCallEGADS(EG_getBodyTopos, (body, fobjs[ii], NODE, &origNn, &nobjsOrigFace));
4691*5552b385SBrandon 
4692*5552b385SBrandon         double minVal = 1.0E10;
4693*5552b385SBrandon         double evalCheck[18];
4694*5552b385SBrandon         int    equivOrigNodeID = -1;
4695*5552b385SBrandon         for (int mm = 0; mm < origNn; ++mm) {
4696*5552b385SBrandon           double delta = 1.0E10;
4697*5552b385SBrandon           if (islite) PetscCallEGADS(EGlite_evaluate, (nobjsOrigFace[mm], NULL, evalCheck));
4698*5552b385SBrandon           else PetscCallEGADS(EG_evaluate, (nobjsOrigFace[mm], NULL, evalCheck));
4699*5552b385SBrandon 
4700*5552b385SBrandon           delta = PetscSqrtReal(PetscSqr(evalCheck[0] - eval[0]) + PetscSqr(evalCheck[1] - eval[1]) + PetscSqr(evalCheck[2] - eval[2]));
4701*5552b385SBrandon 
4702*5552b385SBrandon           if (delta < minVal) {
4703*5552b385SBrandon             if (islite) equivOrigNodeID = EGlite_indexBodyTopo(body, nobjsOrigFace[mm]);
4704*5552b385SBrandon             else equivOrigNodeID = EG_indexBodyTopo(body, nobjsOrigFace[mm]);
4705*5552b385SBrandon 
4706*5552b385SBrandon             minVal = delta;
4707*5552b385SBrandon           }
4708*5552b385SBrandon         }
4709*5552b385SBrandon         // Could be replaced with DMPlexFreeGeomObject
4710*5552b385SBrandon         if (islite) EGlite_free(nobjsOrigFace);
4711*5552b385SBrandon         else EG_free(nobjsOrigFace);
4712*5552b385SBrandon 
4713*5552b385SBrandon         // New Body
4714*5552b385SBrandon         ego *nobjsNewFace;
4715*5552b385SBrandon         int  newNn;
4716*5552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getBodyTopos, (newbody, nfobjs[ii], NODE, &newNn, &nobjsNewFace));
4717*5552b385SBrandon         else PetscCallEGADS(EG_getBodyTopos, (newbody, nfobjs[ii], NODE, &newNn, &nobjsNewFace));
4718*5552b385SBrandon 
4719*5552b385SBrandon         minVal             = 1.0E10;
4720*5552b385SBrandon         int equivNewNodeID = -1;
4721*5552b385SBrandon         for (int mm = 0; mm < newNn; ++mm) {
4722*5552b385SBrandon           double delta = 1.0E10;
4723*5552b385SBrandon           if (islite) PetscCallEGADS(EGlite_evaluate, (nobjsNewFace[mm], NULL, evalCheck));
4724*5552b385SBrandon           else PetscCallEGADS(EG_evaluate, (nobjsNewFace[mm], NULL, evalCheck));
4725*5552b385SBrandon 
4726*5552b385SBrandon           delta = PetscSqrtReal(PetscSqr(evalCheck[0] - eval[0]) + PetscSqr(evalCheck[1] - eval[1]) + PetscSqr(evalCheck[2] - eval[2]));
4727*5552b385SBrandon 
4728*5552b385SBrandon           if (delta < minVal) {
4729*5552b385SBrandon             if (islite) equivNewNodeID = EGlite_indexBodyTopo(newbody, nobjsNewFace[mm]);
4730*5552b385SBrandon             else equivNewNodeID = EG_indexBodyTopo(newbody, nobjsNewFace[mm]);
4731*5552b385SBrandon 
4732*5552b385SBrandon             minVal = delta;
4733*5552b385SBrandon           }
4734*5552b385SBrandon         }
4735*5552b385SBrandon         if (islite) EGlite_free(nobjsNewFace);
4736*5552b385SBrandon         else EG_free(nobjsNewFace);
4737*5552b385SBrandon 
4738*5552b385SBrandon         // Store equivalent NODE IDs
4739*5552b385SBrandon         nodeIDEquiv[equivOrigNodeID] = equivNewNodeID;
4740*5552b385SBrandon       }
4741*5552b385SBrandon     }
4742*5552b385SBrandon   }
4743*5552b385SBrandon 
4744*5552b385SBrandon   // Find Equivalent EDGEs
4745*5552b385SBrandon   //   Get total number of EDGEs on Original Geometry
4746*5552b385SBrandon   int  totalNumEdge;
4747*5552b385SBrandon   ego *eobjsOrig;
4748*5552b385SBrandon   if (islite) {
4749*5552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, EDGE, &totalNumEdge, &eobjsOrig));
4750*5552b385SBrandon     EGlite_free(eobjsOrig);
4751*5552b385SBrandon   } else {
4752*5552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (body, NULL, EDGE, &totalNumEdge, &eobjsOrig));
4753*5552b385SBrandon     EG_free(eobjsOrig);
4754*5552b385SBrandon   }
4755*5552b385SBrandon 
4756*5552b385SBrandon   //   Get total number of EDGEs on New Geometry
4757*5552b385SBrandon   int  totalNumEdgeNew;
4758*5552b385SBrandon   ego *eobjsNew;
4759*5552b385SBrandon   if (islite) {
4760*5552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (newbody, NULL, EDGE, &totalNumEdgeNew, &eobjsNew));
4761*5552b385SBrandon     EGlite_free(eobjsNew);
4762*5552b385SBrandon   } else {
4763*5552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (newbody, NULL, EDGE, &totalNumEdgeNew, &eobjsNew));
4764*5552b385SBrandon     EG_free(eobjsNew);
4765*5552b385SBrandon   }
4766*5552b385SBrandon 
4767*5552b385SBrandon   // Initialize EDGE ID equivalent vector
4768*5552b385SBrandon   // FORMAT :: vector index is the Original Geometry's EDGE ID, the vector Value is the New Geometry's EDGE ID
4769*5552b385SBrandon   int edgeIDEquiv[totalNumEdge + 1];
4770*5552b385SBrandon 
4771*5552b385SBrandon   // Find Equivalent EDGEs
4772*5552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
4773*5552b385SBrandon     // Get Original Geometry EDGE's NODEs
4774*5552b385SBrandon     int numOrigEdge, numNewEdge;
4775*5552b385SBrandon     if (islite) {
4776*5552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (body, fobjs[ii], EDGE, &numOrigEdge, &eobjsOrig));
4777*5552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (newbody, nfobjs[ii], EDGE, &numNewEdge, &eobjsNew));
4778*5552b385SBrandon     } else {
4779*5552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (body, fobjs[ii], EDGE, &numOrigEdge, &eobjsOrig));
4780*5552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (newbody, nfobjs[ii], EDGE, &numNewEdge, &eobjsNew));
4781*5552b385SBrandon     }
4782*5552b385SBrandon 
4783*5552b385SBrandon     // new loop below
4784*5552b385SBrandon     for (int nn = 0; nn < numOrigEdge; ++nn) {
4785*5552b385SBrandon       ego origEdge = eobjsOrig[nn];
4786*5552b385SBrandon       ego geomEdgeOrig, *nobjsOrig;
4787*5552b385SBrandon       int oclassEdgeOrig, mtypeEdgeOrig;
4788*5552b385SBrandon       int NnOrig, *nsensesEdgeOrig;
4789*5552b385SBrandon 
4790*5552b385SBrandon       if (islite) PetscCallEGADS(EGlite_getTopology, (origEdge, &geomEdgeOrig, &oclassEdgeOrig, &mtypeEdgeOrig, NULL, &NnOrig, &nobjsOrig, &nsensesEdgeOrig));
4791*5552b385SBrandon       else PetscCallEGADS(EG_getTopology, (origEdge, &geomEdgeOrig, &oclassEdgeOrig, &mtypeEdgeOrig, NULL, &NnOrig, &nobjsOrig, &nsensesEdgeOrig));
4792*5552b385SBrandon 
4793*5552b385SBrandon       PetscBool isSame = PETSC_FALSE;
4794*5552b385SBrandon       for (int jj = 0; jj < numNewEdge; ++jj) {
4795*5552b385SBrandon         ego newEdge = eobjsNew[jj];
4796*5552b385SBrandon         ego geomEdgeNew, *nobjsNew;
4797*5552b385SBrandon         int oclassEdgeNew, mtypeEdgeNew;
4798*5552b385SBrandon         int NnNew, *nsensesEdgeNew;
4799*5552b385SBrandon 
4800*5552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getTopology, (newEdge, &geomEdgeNew, &oclassEdgeNew, &mtypeEdgeNew, NULL, &NnNew, &nobjsNew, &nsensesEdgeNew));
4801*5552b385SBrandon         else PetscCallEGADS(EG_getTopology, (newEdge, &geomEdgeNew, &oclassEdgeNew, &mtypeEdgeNew, NULL, &NnNew, &nobjsNew, &nsensesEdgeNew));
4802*5552b385SBrandon 
4803*5552b385SBrandon         if (mtypeEdgeOrig == mtypeEdgeNew) {
4804*5552b385SBrandon           // Only operate if the EDGE types are the same
4805*5552b385SBrandon           for (int kk = 0; kk < NnNew; ++kk) {
4806*5552b385SBrandon             int nodeIDOrigGeom, nodeIDNewGeom;
4807*5552b385SBrandon             if (islite) {
4808*5552b385SBrandon               nodeIDOrigGeom = EGlite_indexBodyTopo(body, nobjsOrig[kk]);
4809*5552b385SBrandon               nodeIDNewGeom  = EGlite_indexBodyTopo(newbody, nobjsNew[kk]);
4810*5552b385SBrandon             } else {
4811*5552b385SBrandon               nodeIDOrigGeom = EG_indexBodyTopo(body, nobjsOrig[kk]);
4812*5552b385SBrandon               nodeIDNewGeom  = EG_indexBodyTopo(newbody, nobjsNew[kk]);
4813*5552b385SBrandon             }
4814*5552b385SBrandon 
4815*5552b385SBrandon             if (nodeIDNewGeom == nodeIDEquiv[nodeIDOrigGeom]) {
4816*5552b385SBrandon               isSame = PETSC_TRUE;
4817*5552b385SBrandon             } else {
4818*5552b385SBrandon               isSame = PETSC_FALSE;
4819*5552b385SBrandon               kk     = NnNew; // skip ahead because first NODE failed test and order is important
4820*5552b385SBrandon             }
4821*5552b385SBrandon           }
4822*5552b385SBrandon 
4823*5552b385SBrandon           if (isSame == PETSC_TRUE) {
4824*5552b385SBrandon             int edgeIDOrig, edgeIDNew;
4825*5552b385SBrandon             if (islite) {
4826*5552b385SBrandon               edgeIDOrig = EGlite_indexBodyTopo(body, origEdge);
4827*5552b385SBrandon               edgeIDNew  = EGlite_indexBodyTopo(newbody, newEdge);
4828*5552b385SBrandon             } else {
4829*5552b385SBrandon               edgeIDOrig = EG_indexBodyTopo(body, origEdge);
4830*5552b385SBrandon               edgeIDNew  = EG_indexBodyTopo(newbody, newEdge);
4831*5552b385SBrandon             }
4832*5552b385SBrandon 
4833*5552b385SBrandon             edgeIDEquiv[edgeIDOrig] = edgeIDNew;
4834*5552b385SBrandon             jj                      = numNewEdge;
4835*5552b385SBrandon           }
4836*5552b385SBrandon         }
4837*5552b385SBrandon       }
4838*5552b385SBrandon     }
4839*5552b385SBrandon     if (islite) {
4840*5552b385SBrandon       EGlite_free(eobjsOrig);
4841*5552b385SBrandon       EGlite_free(eobjsNew);
4842*5552b385SBrandon     } else {
4843*5552b385SBrandon       EG_free(eobjsOrig);
4844*5552b385SBrandon       EG_free(eobjsNew);
4845*5552b385SBrandon     }
4846*5552b385SBrandon   }
4847*5552b385SBrandon   if (islite) {
4848*5552b385SBrandon     EGlite_free(fobjs);
4849*5552b385SBrandon     EGlite_free(nfobjs);
4850*5552b385SBrandon   } else {
4851*5552b385SBrandon     EG_free(fobjs);
4852*5552b385SBrandon     EG_free(nfobjs);
4853*5552b385SBrandon   }
4854*5552b385SBrandon 
4855*5552b385SBrandon   // Modify labels to point to the IDs on the new Geometry
4856*5552b385SBrandon   IS isNodeID, isEdgeID;
4857*5552b385SBrandon 
4858*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
4859*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
4860*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
4861*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
4862*5552b385SBrandon 
4863*5552b385SBrandon   PetscCall(ISCreateGeneral(comm, totalNumNode + 1, nodeIDEquiv, PETSC_COPY_VALUES, &isNodeID));
4864*5552b385SBrandon   PetscCall(ISCreateGeneral(comm, totalNumEdge + 1, edgeIDEquiv, PETSC_COPY_VALUES, &isEdgeID));
4865*5552b385SBrandon   /* Do not perform check. Np may != Nv due to Degenerate Geometry which is not stored in labels.               */
4866*5552b385SBrandon   /* We do not know in advance which IDs have been omitted. This may also change due to geometry modifications. */
4867*5552b385SBrandon   PetscCall(DMLabelRewriteValues(vertexLabel, isNodeID));
4868*5552b385SBrandon   PetscCall(DMLabelRewriteValues(edgeLabel, isEdgeID));
4869*5552b385SBrandon   PetscCall(ISDestroy(&isNodeID));
4870*5552b385SBrandon   PetscCall(ISDestroy(&isEdgeID));
4871*5552b385SBrandon 
4872*5552b385SBrandon   // Attempt to point to the new geometry
4873*5552b385SBrandon   PetscCallEGADS(EG_deleteObject, (model));
4874*5552b385SBrandon   PetscCall(PetscContainerSetPointer(modelObj, newmodel));
4875*5552b385SBrandon 
4876*5552b385SBrandon   // save updated model to file
4877*5552b385SBrandon   if (saveGeom == PETSC_TRUE && stpName != NULL) PetscCall(EG_saveModel(newmodel, stpName));
4878*5552b385SBrandon 
4879*5552b385SBrandon   // Inflate Mesh to EGADS Model
4880*5552b385SBrandon   if (autoInflate == PETSC_TRUE) PetscCall(DMPlexInflateToGeomModel(dm, PETSC_TRUE));
4881*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
4882*5552b385SBrandon #else
4883*5552b385SBrandon   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
4884*5552b385SBrandon #endif
4885*5552b385SBrandon }
4886*5552b385SBrandon 
4887*5552b385SBrandon /*@C
4888*5552b385SBrandon   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.
4889*5552b385SBrandon 
4890*5552b385SBrandon   Collective
4891*5552b385SBrandon 
4892*5552b385SBrandon   Input Parameter:
4893*5552b385SBrandon . dm - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
4894*5552b385SBrandon 
4895*5552b385SBrandon   Level: intermediate
4896*5552b385SBrandon 
4897*5552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`
4898*5552b385SBrandon @*/
4899*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelTUV(DM dm)
4900*5552b385SBrandon {
4901*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
4902*5552b385SBrandon   /* EGADS Variables */
4903*5552b385SBrandon   ego    model, geom, body, face, edge;
4904*5552b385SBrandon   ego   *bodies;
4905*5552b385SBrandon   int    Nb, oclass, mtype, *senses;
4906*5552b385SBrandon   double result[4];
4907*5552b385SBrandon   /* PETSc Variables */
4908*5552b385SBrandon   DM             cdm;
4909*5552b385SBrandon   PetscContainer modelObj;
4910*5552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
4911*5552b385SBrandon   Vec            coordinates;
4912*5552b385SBrandon   PetscScalar   *coords;
4913*5552b385SBrandon   PetscInt       bodyID, faceID, edgeID, vertexID;
4914*5552b385SBrandon   PetscInt       cdim, vStart, vEnd, v;
4915*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
4916*5552b385SBrandon #endif
4917*5552b385SBrandon 
4918*5552b385SBrandon   PetscFunctionBegin;
4919*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
4920*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
4921*5552b385SBrandon   if (!modelObj) {
4922*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
4923*5552b385SBrandon     islite = PETSC_TRUE;
4924*5552b385SBrandon   }
4925*5552b385SBrandon   if (!modelObj) PetscFunctionReturn(0);
4926*5552b385SBrandon 
4927*5552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &cdim));
4928*5552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
4929*5552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
4930*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
4931*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
4932*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
4933*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
4934*5552b385SBrandon 
4935*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
4936*5552b385SBrandon 
4937*5552b385SBrandon   if (islite) PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
4938*5552b385SBrandon   else PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
4939*5552b385SBrandon 
4940*5552b385SBrandon   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
4941*5552b385SBrandon   PetscCall(VecGetArrayWrite(coordinates, &coords));
4942*5552b385SBrandon 
4943*5552b385SBrandon   // Define t, u, v arrays to be stored in a PetscContainer after populated
4944*5552b385SBrandon   PetscScalar *t_point, *u_point, *v_point;
4945*5552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &t_point));
4946*5552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &u_point));
4947*5552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &v_point));
4948*5552b385SBrandon 
4949*5552b385SBrandon   for (v = vStart; v < vEnd; ++v) {
4950*5552b385SBrandon     PetscScalar *vcoords;
4951*5552b385SBrandon 
4952*5552b385SBrandon     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
4953*5552b385SBrandon     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
4954*5552b385SBrandon     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
4955*5552b385SBrandon     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
4956*5552b385SBrandon 
4957*5552b385SBrandon     // TODO Figure out why this is unknown sometimes
4958*5552b385SBrandon     if (bodyID < 0 && Nb == 1) bodyID = 0;
4959*5552b385SBrandon     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);
4960c1cad2e7SMatthew G. Knepley     body = bodies[bodyID];
4961c1cad2e7SMatthew G. Knepley 
49629566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
4963c1cad2e7SMatthew G. Knepley     if (edgeID > 0) {
4964c1cad2e7SMatthew G. Knepley       /* Snap to EDGE at nearest location */
4965c1cad2e7SMatthew G. Knepley       double params[1];
4966*5552b385SBrandon 
4967*5552b385SBrandon       if (islite) {
4968*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
4969*5552b385SBrandon         PetscCall(EGlite_invEvaluate(edge, vcoords, params, result));
4970*5552b385SBrandon       } // Get (t) of nearest point on EDGE
4971*5552b385SBrandon       else {
49729566063dSJacob Faibussowitsch         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
4973*5552b385SBrandon         PetscCall(EG_invEvaluate(edge, vcoords, params, result));
4974*5552b385SBrandon       } // Get (t) of nearest point on EDGE
4975*5552b385SBrandon 
4976*5552b385SBrandon       t_point[v - vStart] = params[0];
4977*5552b385SBrandon       u_point[v - vStart] = 0.0;
4978*5552b385SBrandon       v_point[v - vStart] = 0.0;
4979c1cad2e7SMatthew G. Knepley     } else if (faceID > 0) {
4980c1cad2e7SMatthew G. Knepley       /* Snap to FACE at nearest location */
4981c1cad2e7SMatthew G. Knepley       double params[2];
4982*5552b385SBrandon 
4983*5552b385SBrandon       if (islite) {
4984*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
4985*5552b385SBrandon         PetscCall(EGlite_invEvaluate(face, vcoords, params, result));
4986*5552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
4987*5552b385SBrandon       else {
49889566063dSJacob Faibussowitsch         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
4989*5552b385SBrandon         PetscCall(EG_invEvaluate(face, vcoords, params, result));
4990*5552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
4991*5552b385SBrandon 
4992*5552b385SBrandon       t_point[v - vStart] = 0.0;
4993*5552b385SBrandon       u_point[v - vStart] = params[0];
4994*5552b385SBrandon       v_point[v - vStart] = params[1];
4995*5552b385SBrandon     } else {
4996*5552b385SBrandon       t_point[v - vStart] = 0.0;
4997*5552b385SBrandon       u_point[v - vStart] = 0.0;
4998*5552b385SBrandon       v_point[v - vStart] = 0.0;
4999*5552b385SBrandon     }
5000*5552b385SBrandon   }
5001*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5002*5552b385SBrandon   /* Clear out global coordinates */
5003*5552b385SBrandon   PetscCall(VecDestroy(&dm->coordinates[0].x));
5004*5552b385SBrandon 
5005*5552b385SBrandon   /* Store in PetscContainters */
5006*5552b385SBrandon   {
5007*5552b385SBrandon     PetscContainer t_pointObj, u_pointObj, v_pointObj;
5008*5552b385SBrandon 
5009*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Edge t Parameter", (PetscObject *)&t_pointObj));
5010*5552b385SBrandon     if (!t_pointObj) {
5011*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &t_pointObj));
5012*5552b385SBrandon       PetscCall(PetscContainerSetPointer(t_pointObj, t_point));
5013*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Edge t Parameter", (PetscObject)t_pointObj));
5014*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(t_pointObj, PetscCtxDestroyDefault));
5015*5552b385SBrandon       PetscCall(PetscContainerDestroy(&t_pointObj));
5016*5552b385SBrandon     } else {
5017*5552b385SBrandon       void *old;
5018*5552b385SBrandon 
5019*5552b385SBrandon       PetscCall(PetscContainerGetPointer(t_pointObj, &old));
5020*5552b385SBrandon       PetscCall(PetscFree(old));
5021*5552b385SBrandon       PetscCall(PetscContainerSetPointer(t_pointObj, t_point));
5022*5552b385SBrandon     }
5023*5552b385SBrandon 
5024*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face u Parameter", (PetscObject *)&u_pointObj));
5025*5552b385SBrandon     if (!u_pointObj) {
5026*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &u_pointObj));
5027*5552b385SBrandon       PetscCall(PetscContainerSetPointer(u_pointObj, u_point));
5028*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Face u Parameter", (PetscObject)u_pointObj));
5029*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(u_pointObj, PetscCtxDestroyDefault));
5030*5552b385SBrandon       PetscCall(PetscContainerDestroy(&u_pointObj));
5031*5552b385SBrandon     } else {
5032*5552b385SBrandon       void *old;
5033*5552b385SBrandon 
5034*5552b385SBrandon       PetscCall(PetscContainerGetPointer(u_pointObj, &old));
5035*5552b385SBrandon       PetscCall(PetscFree(old));
5036*5552b385SBrandon       PetscCall(PetscContainerSetPointer(u_pointObj, u_point));
5037*5552b385SBrandon     }
5038*5552b385SBrandon 
5039*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face v Parameter", (PetscObject *)&v_pointObj));
5040*5552b385SBrandon     if (!v_pointObj) {
5041*5552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &v_pointObj));
5042*5552b385SBrandon       PetscCall(PetscContainerSetPointer(v_pointObj, v_point));
5043*5552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Face v Parameter", (PetscObject)v_pointObj));
5044*5552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(v_pointObj, PetscCtxDestroyDefault));
5045*5552b385SBrandon       PetscCall(PetscContainerDestroy(&v_pointObj));
5046*5552b385SBrandon     } else {
5047*5552b385SBrandon       void *old;
5048*5552b385SBrandon 
5049*5552b385SBrandon       PetscCall(PetscContainerGetPointer(v_pointObj, &old));
5050*5552b385SBrandon       PetscCall(PetscFree(old));
5051*5552b385SBrandon       PetscCall(PetscContainerSetPointer(v_pointObj, v_point));
5052*5552b385SBrandon     }
5053*5552b385SBrandon   }
5054*5552b385SBrandon #endif
5055*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5056*5552b385SBrandon }
5057*5552b385SBrandon 
5058*5552b385SBrandon /*@C
5059*5552b385SBrandon   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().
5060*5552b385SBrandon 
5061*5552b385SBrandon   Collective
5062*5552b385SBrandon 
5063*5552b385SBrandon   Input Parameter:
5064*5552b385SBrandon . dm - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
5065*5552b385SBrandon 
5066*5552b385SBrandon   Level: intermediate
5067*5552b385SBrandon 
5068*5552b385SBrandon   Note:
5069*5552b385SBrandon   The updated DM object inflated to the associated underlying geometry. This updates the [x, y, z] coordinates of DM points associated with geometry.
5070*5552b385SBrandon 
5071*5552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`, `DMPlexGetGeomModelTUV()`
5072*5552b385SBrandon @*/
5073*5552b385SBrandon PetscErrorCode DMPlexInflateToGeomModelUseTUV(DM dm)
5074*5552b385SBrandon {
5075*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
5076*5552b385SBrandon   /* EGADS Variables */
5077*5552b385SBrandon   ego    model, geom, body, face, edge, vertex;
5078*5552b385SBrandon   ego   *bodies;
5079*5552b385SBrandon   int    Nb, oclass, mtype, *senses;
5080*5552b385SBrandon   double result[18], params[2];
5081*5552b385SBrandon   /* PETSc Variables */
5082*5552b385SBrandon   DM             cdm;
5083*5552b385SBrandon   PetscContainer modelObj;
5084*5552b385SBrandon   PetscContainer t_pointObj, u_pointObj, v_pointObj;
5085*5552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
5086*5552b385SBrandon   Vec            coordinates;
5087*5552b385SBrandon   PetscScalar   *coords;
5088*5552b385SBrandon   PetscScalar   *t_point, *u_point, *v_point;
5089*5552b385SBrandon   PetscInt       bodyID, faceID, edgeID, vertexID;
5090*5552b385SBrandon   PetscInt       cdim, d, vStart, vEnd, v;
5091*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5092*5552b385SBrandon #endif
5093*5552b385SBrandon 
5094*5552b385SBrandon   PetscFunctionBegin;
5095*5552b385SBrandon #if defined(PETSC_HAVE_EGADS)
5096*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5097*5552b385SBrandon   if (!modelObj) {
5098*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5099*5552b385SBrandon     islite = PETSC_TRUE;
5100*5552b385SBrandon   }
5101*5552b385SBrandon 
5102*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Edge t Parameter", (PetscObject *)&t_pointObj));
5103*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face u Parameter", (PetscObject *)&u_pointObj));
5104*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face v Parameter", (PetscObject *)&v_pointObj));
5105*5552b385SBrandon 
5106*5552b385SBrandon   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
5107*5552b385SBrandon   if (!t_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
5108*5552b385SBrandon   if (!u_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
5109*5552b385SBrandon   if (!v_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
5110*5552b385SBrandon 
5111*5552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &cdim));
5112*5552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
5113*5552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
5114*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
5115*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
5116*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
5117*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
5118*5552b385SBrandon 
5119*5552b385SBrandon   PetscCall(PetscContainerGetPointer(t_pointObj, (void **)&t_point));
5120*5552b385SBrandon   PetscCall(PetscContainerGetPointer(u_pointObj, (void **)&u_point));
5121*5552b385SBrandon   PetscCall(PetscContainerGetPointer(v_pointObj, (void **)&v_point));
5122*5552b385SBrandon 
5123*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
5124*5552b385SBrandon 
5125*5552b385SBrandon   if (islite) {
5126*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
5127*5552b385SBrandon   } else {
5128*5552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
5129*5552b385SBrandon   }
5130*5552b385SBrandon 
5131*5552b385SBrandon   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5132*5552b385SBrandon   PetscCall(VecGetArrayWrite(coordinates, &coords));
5133*5552b385SBrandon 
5134*5552b385SBrandon   for (v = vStart; v < vEnd; ++v) {
5135*5552b385SBrandon     PetscScalar *vcoords;
5136*5552b385SBrandon 
5137*5552b385SBrandon     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
5138*5552b385SBrandon     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
5139*5552b385SBrandon     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
5140*5552b385SBrandon     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
5141*5552b385SBrandon 
5142*5552b385SBrandon     // TODO Figure out why this is unknown sometimes
5143*5552b385SBrandon     if (bodyID < 0 && Nb == 1) bodyID = 0;
5144*5552b385SBrandon     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);
5145*5552b385SBrandon     body = bodies[bodyID];
5146*5552b385SBrandon 
5147*5552b385SBrandon     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
5148*5552b385SBrandon     if (vertexID > 0) {
5149*5552b385SBrandon       /* Snap to Vertices */
5150*5552b385SBrandon       if (islite) {
5151*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, NODE, vertexID, &vertex));
5152*5552b385SBrandon         PetscCall(EGlite_evaluate(vertex, NULL, result));
5153*5552b385SBrandon       } else {
5154*5552b385SBrandon         PetscCall(EG_objectBodyTopo(body, NODE, vertexID, &vertex));
5155*5552b385SBrandon         PetscCall(EG_evaluate(vertex, NULL, result));
5156*5552b385SBrandon       }
5157*5552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
5158*5552b385SBrandon     } else if (edgeID > 0) {
5159*5552b385SBrandon       /* Snap to EDGE */
5160*5552b385SBrandon       params[0] = t_point[v - vStart];
5161*5552b385SBrandon       if (islite) {
5162*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
5163*5552b385SBrandon         PetscCall(EGlite_evaluate(edge, params, result));
5164*5552b385SBrandon       } else {
5165*5552b385SBrandon         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
5166*5552b385SBrandon         PetscCall(EG_evaluate(edge, params, result));
5167*5552b385SBrandon       }
5168*5552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
5169*5552b385SBrandon     } else if (faceID > 0) {
5170*5552b385SBrandon       /* Snap to FACE */
5171*5552b385SBrandon       params[0] = u_point[v - vStart];
5172*5552b385SBrandon       params[1] = v_point[v - vStart];
5173*5552b385SBrandon       if (islite) {
5174*5552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
5175*5552b385SBrandon         PetscCall(EGlite_evaluate(face, params, result));
5176*5552b385SBrandon       } else {
5177*5552b385SBrandon         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
5178*5552b385SBrandon         PetscCall(EG_evaluate(face, params, result));
5179*5552b385SBrandon       }
5180c1cad2e7SMatthew G. Knepley       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
5181c1cad2e7SMatthew G. Knepley     }
5182c1cad2e7SMatthew G. Knepley   }
51839566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5184c1cad2e7SMatthew G. Knepley   /* Clear out global coordinates */
51856858538eSMatthew G. Knepley   PetscCall(VecDestroy(&dm->coordinates[0].x));
5186c1cad2e7SMatthew G. Knepley #endif
51873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5188c1cad2e7SMatthew G. Knepley }
5189c1cad2e7SMatthew G. Knepley 
5190cc4c1da9SBarry Smith /*@
5191*5552b385SBrandon   DMPlexInflateToGeomModel - Wrapper function allowing two methods for inflating refined meshes to the underlying geometric domain.
51927bee2925SMatthew Knepley 
51937bee2925SMatthew Knepley   Collective
51947bee2925SMatthew Knepley 
51957bee2925SMatthew Knepley   Input Parameters:
5196*5552b385SBrandon + dm     - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5197*5552b385SBrandon - useTUV - PetscBool indicating if the user would like to inflate the DMPlex to the underlying geometry
5198*5552b385SBrandon            using (t) for nodes on EDGEs and (u, v) for nodes on FACEs or using the nodes (x, y, z) coordinates
5199*5552b385SBrandon            and shortest distance routine.
5200*5552b385SBrandon             If useTUV = PETSC_TRUE, use the (t) or (u, v) parameters to inflate the DMPlex to the CAD geometry.
5201*5552b385SBrandon             If useTUV = PETSC_FALSE, use the nodes (x, y, z) coordinates and the shortest disctance routine.
5202*5552b385SBrandon 
5203*5552b385SBrandon   Notes:
5204*5552b385SBrandon   DM with nodal coordinates modified so that they lie on the EDGEs and FACEs of the underlying geometry.
5205*5552b385SBrandon 
5206*5552b385SBrandon   (t) and (u, v) parameters for all DMPlex nodes on EDGEs and FACEs are stored in arrays within PetscContainers attached to the DM.
5207*5552b385SBrandon   The containers have names "Point - Edge t Parameter", "Point - Face u Parameter", and "Point - Face v Parameter".
5208*5552b385SBrandon   The arrays are organized by Point 0-based ID (i.e. [v-vstart] as defined in the DMPlex.
5209*5552b385SBrandon 
5210*5552b385SBrandon   Level: intermediate
5211*5552b385SBrandon 
5212*5552b385SBrandon .seealso: `DMPlexGetGeomModelTUV()`, `DMPlexInflateToGeomModelUseTUV()`, `DMPlexInflateToGeomModelUseXYZ()`
5213*5552b385SBrandon @*/
5214*5552b385SBrandon PetscErrorCode DMPlexInflateToGeomModel(DM dm, PetscBool useTUV)
5215*5552b385SBrandon {
5216*5552b385SBrandon   PetscFunctionBeginHot;
5217*5552b385SBrandon   if (useTUV) {
5218*5552b385SBrandon     PetscCall(DMPlexGetGeomModelTUV(dm));
5219*5552b385SBrandon     PetscCall(DMPlexInflateToGeomModelUseTUV(dm));
5220*5552b385SBrandon   } else {
5221*5552b385SBrandon     PetscCall(DMPlexInflateToGeomModelUseXYZ(dm));
5222*5552b385SBrandon   }
5223*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5224*5552b385SBrandon }
5225*5552b385SBrandon 
5226*5552b385SBrandon #ifdef PETSC_HAVE_EGADS
5227*5552b385SBrandon /*@C
5228*5552b385SBrandon   DMPlexGetGeomModelBodies - Returns an array of PetscGeom BODY objects attached to the referenced geomtric model entity as well as the number of BODYs.
5229*5552b385SBrandon 
5230*5552b385SBrandon   Collective
5231*5552b385SBrandon 
5232*5552b385SBrandon   Input Parameter:
5233*5552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5234*5552b385SBrandon 
5235*5552b385SBrandon   Output Parameters:
5236*5552b385SBrandon + bodies    - Array of PetscGeom BODY objects referenced by the geometric model.
5237*5552b385SBrandon - numBodies - Number of BODYs referenced by the geometric model. Also the size of **bodies array.
5238*5552b385SBrandon 
5239*5552b385SBrandon   Level: intermediate
5240*5552b385SBrandon 
5241*5552b385SBrandon .seealso:
5242*5552b385SBrandon @*/
5243*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelBodies(DM dm, PetscGeom **bodies, PetscInt *numBodies)
5244*5552b385SBrandon {
5245*5552b385SBrandon   PetscFunctionBeginHot;
5246*5552b385SBrandon   PetscContainer modelObj;
5247*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5248*5552b385SBrandon   ego            model, geom;
5249*5552b385SBrandon   int            oclass, mtype;
5250*5552b385SBrandon   int           *senses;
5251*5552b385SBrandon 
5252*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5253*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5254*5552b385SBrandon   if (!modelObj) {
5255*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5256*5552b385SBrandon     islite = PETSC_TRUE;
5257*5552b385SBrandon   }
5258*5552b385SBrandon 
5259*5552b385SBrandon   // Get attached EGADS or EGADSlite model (pointer)
5260*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
5261*5552b385SBrandon 
5262*5552b385SBrandon   if (islite) {
5263*5552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, numBodies, bodies, &senses));
5264*5552b385SBrandon   } else {
5265*5552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, numBodies, bodies, &senses));
5266*5552b385SBrandon   }
5267*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5268*5552b385SBrandon }
5269*5552b385SBrandon 
5270*5552b385SBrandon /*@C
5271*5552b385SBrandon   DMPlexGetGeomModelBodyShells - Returns an array of PetscGeom SHELL objects attached to the referenced BODY geomtric entity as well as the number of SHELLs.
5272*5552b385SBrandon 
5273*5552b385SBrandon   Collective
5274*5552b385SBrandon 
5275*5552b385SBrandon   Input Parameters:
5276*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5277*5552b385SBrandon - body - PetscGeom BODY object containing the SHELL objects of interest.
5278*5552b385SBrandon 
5279*5552b385SBrandon   Output Parameters:
5280*5552b385SBrandon + shells    - Array of PetscGeom SHELL objects referenced by the PetscGeom BODY object
5281*5552b385SBrandon - numShells - Number of SHELLs referenced by the PetscGeom BODY object. Also the size of **shells array.
5282*5552b385SBrandon 
5283*5552b385SBrandon   Level: intermediate
5284*5552b385SBrandon 
5285*5552b385SBrandon .seealso:
5286*5552b385SBrandon @*/
5287*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelBodyShells(DM dm, PetscGeom body, PetscGeom **shells, PetscInt *numShells)
5288*5552b385SBrandon {
5289*5552b385SBrandon   PetscFunctionBeginHot;
5290*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5291*5552b385SBrandon   PetscContainer modelObj;
5292*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5293*5552b385SBrandon 
5294*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5295*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5296*5552b385SBrandon   if (!modelObj) {
5297*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5298*5552b385SBrandon     islite = PETSC_TRUE;
5299*5552b385SBrandon   }
5300*5552b385SBrandon 
5301*5552b385SBrandon   if (islite) {
5302*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, SHELL, numShells, shells));
5303*5552b385SBrandon   } else {
5304*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, SHELL, numShells, shells));
5305*5552b385SBrandon   }
5306*5552b385SBrandon   #endif
5307*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5308*5552b385SBrandon }
5309*5552b385SBrandon 
5310*5552b385SBrandon /*@C
5311*5552b385SBrandon   DMPlexGetGeomModelBodyFaces - Returns an array of PetscGeom FACE objects attached to the referenced BODY geomtric entity as well as the number of FACEs.
5312*5552b385SBrandon 
5313*5552b385SBrandon   Collective
5314*5552b385SBrandon 
5315*5552b385SBrandon   Input Parameters:
5316*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5317*5552b385SBrandon - body - PetscGeom BODY object containing the FACE objects of interest.
5318*5552b385SBrandon 
5319*5552b385SBrandon   Output Parameters:
5320*5552b385SBrandon + faces    - Array of PetscGeom FACE objects referenced by the PetscGeom BODY object
5321*5552b385SBrandon - numFaces - Number of FACEs referenced by the PetscGeom BODY object. Also the size of **faces array.
5322*5552b385SBrandon 
5323*5552b385SBrandon   Level: intermediate
5324*5552b385SBrandon 
5325*5552b385SBrandon .seealso:
5326*5552b385SBrandon @*/
5327*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelBodyFaces(DM dm, PetscGeom body, PetscGeom **faces, PetscInt *numFaces)
5328*5552b385SBrandon {
5329*5552b385SBrandon   PetscFunctionBeginHot;
5330*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5331*5552b385SBrandon   PetscContainer modelObj;
5332*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5333*5552b385SBrandon 
5334*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5335*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5336*5552b385SBrandon   if (!modelObj) {
5337*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5338*5552b385SBrandon     islite = PETSC_TRUE;
5339*5552b385SBrandon   }
5340*5552b385SBrandon 
5341*5552b385SBrandon   if (islite) {
5342*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, numFaces, faces));
5343*5552b385SBrandon   } else {
5344*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, numFaces, faces));
5345*5552b385SBrandon   }
5346*5552b385SBrandon   #endif
5347*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5348*5552b385SBrandon }
5349*5552b385SBrandon 
5350*5552b385SBrandon /*@C
5351*5552b385SBrandon   DMPlexGetGeomModelBodyLoops - Returns an array of PetscGeom Loop objects attached to the referenced BODY geomtric entity as well as the number of LOOPs.
5352*5552b385SBrandon 
5353*5552b385SBrandon   Collective
5354*5552b385SBrandon 
5355*5552b385SBrandon   Input Parameters:
5356*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5357*5552b385SBrandon - body - PetscGeom BODY object containing the LOOP objects of interest.
5358*5552b385SBrandon 
5359*5552b385SBrandon   Output Parameters:
5360*5552b385SBrandon + loops    - Array of PetscGeom FACE objects referenced by the PetscGeom SHELL object
5361*5552b385SBrandon - numLoops - Number of LOOPs referenced by the PetscGeom BODY object. Also the size of **loops array.
5362*5552b385SBrandon 
5363*5552b385SBrandon   Level: intermediate
5364*5552b385SBrandon 
5365*5552b385SBrandon .seealso:
5366*5552b385SBrandon @*/
5367*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelBodyLoops(DM dm, PetscGeom body, PetscGeom **loops, PetscInt *numLoops)
5368*5552b385SBrandon {
5369*5552b385SBrandon   PetscFunctionBeginHot;
5370*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5371*5552b385SBrandon   PetscContainer modelObj;
5372*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5373*5552b385SBrandon 
5374*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5375*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5376*5552b385SBrandon   if (!modelObj) {
5377*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5378*5552b385SBrandon     islite = PETSC_TRUE;
5379*5552b385SBrandon   }
5380*5552b385SBrandon 
5381*5552b385SBrandon   if (islite) {
5382*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, numLoops, loops));
5383*5552b385SBrandon   } else {
5384*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, LOOP, numLoops, loops));
5385*5552b385SBrandon   }
5386*5552b385SBrandon   #endif
5387*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5388*5552b385SBrandon }
5389*5552b385SBrandon 
5390*5552b385SBrandon /*@C
5391*5552b385SBrandon   DMPlexGetGeomModelShellFaces - Returns an array of PetscGeom FACE objects attached to the referenced SHELL geomtric entity as well as the number of FACEs.
5392*5552b385SBrandon 
5393*5552b385SBrandon   Collective
5394*5552b385SBrandon 
5395*5552b385SBrandon   Input Parameters:
5396*5552b385SBrandon + dm    - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5397*5552b385SBrandon . body  - PetscGeom BODY object containing the FACE objects of interest.
5398*5552b385SBrandon - shell - PetscGeom SHELL object with FACEs of interest.
5399*5552b385SBrandon 
5400*5552b385SBrandon   Output Parameters:
5401*5552b385SBrandon + faces    - Array of PetscGeom FACE objects referenced by the PetscGeom SHELL object
5402*5552b385SBrandon - numFaces - Number of FACEs referenced by the PetscGeom SHELL object. Also the size of **faces array.
5403*5552b385SBrandon 
5404*5552b385SBrandon   Level: intermediate
5405*5552b385SBrandon 
5406*5552b385SBrandon .seealso:
5407*5552b385SBrandon @*/
5408*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelShellFaces(DM dm, PetscGeom body, PetscGeom shell, PetscGeom **faces, PetscInt *numFaces)
5409*5552b385SBrandon {
5410*5552b385SBrandon   PetscFunctionBeginHot;
5411*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5412*5552b385SBrandon   PetscContainer modelObj;
5413*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5414*5552b385SBrandon 
5415*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5416*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5417*5552b385SBrandon   if (!modelObj) {
5418*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5419*5552b385SBrandon     islite = PETSC_TRUE;
5420*5552b385SBrandon   }
5421*5552b385SBrandon 
5422*5552b385SBrandon   if (islite) {
5423*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, shell, FACE, numFaces, faces));
5424*5552b385SBrandon   } else {
5425*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, shell, FACE, numFaces, faces));
5426*5552b385SBrandon   }
5427*5552b385SBrandon   #endif
5428*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5429*5552b385SBrandon }
5430*5552b385SBrandon 
5431*5552b385SBrandon /*@C
5432*5552b385SBrandon   DMPlexGetGeomModelFaceLoops - Returns an array of PetscGeom LOOP objects attached to the referenced FACE geomtric entity as well as the number of LOOPs.
5433*5552b385SBrandon 
5434*5552b385SBrandon   Collective
5435*5552b385SBrandon 
5436*5552b385SBrandon   Input Parameters:
5437*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5438*5552b385SBrandon . body - PetscGeom BODY object containing the LOOP objects of interest.
5439*5552b385SBrandon - face - PetscGeom FACE object with LOOPs of interest.
5440*5552b385SBrandon 
5441*5552b385SBrandon   Output Parameters:
5442*5552b385SBrandon + loops    - Array of PetscGeom LOOP objects referenced by the PetscGeom FACE object
5443*5552b385SBrandon - numLoops - Number of LOOPs referenced by the PetscGeom FACE object. Also the size of **loops array.
5444*5552b385SBrandon 
5445*5552b385SBrandon   Level: intermediate
5446*5552b385SBrandon 
5447*5552b385SBrandon .seealso:
5448*5552b385SBrandon @*/
5449*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelFaceLoops(DM dm, PetscGeom body, PetscGeom face, PetscGeom **loops, PetscInt *numLoops)
5450*5552b385SBrandon {
5451*5552b385SBrandon   PetscFunctionBeginHot;
5452*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5453*5552b385SBrandon   PetscContainer modelObj;
5454*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5455*5552b385SBrandon 
5456*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5457*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5458*5552b385SBrandon   if (!modelObj) {
5459*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5460*5552b385SBrandon     islite = PETSC_TRUE;
5461*5552b385SBrandon   }
5462*5552b385SBrandon 
5463*5552b385SBrandon   if (islite) {
5464*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, face, LOOP, numLoops, loops));
5465*5552b385SBrandon   } else {
5466*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, face, LOOP, numLoops, loops));
5467*5552b385SBrandon   }
5468*5552b385SBrandon   #endif
5469*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5470*5552b385SBrandon }
5471*5552b385SBrandon 
5472*5552b385SBrandon /*@C
5473*5552b385SBrandon   DMPlexGetGeomModelFaceEdges - Returns an array of PetscGeom EDGE objects attached to the referenced FACE geomtric entity as well as the number of EDGEs.
5474*5552b385SBrandon 
5475*5552b385SBrandon   Collective
5476*5552b385SBrandon 
5477*5552b385SBrandon   Input Parameters:
5478*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5479*5552b385SBrandon . body - PetscGeom Body object containing the EDGE objects of interest.
5480*5552b385SBrandon - face - PetscGeom FACE object with EDGEs of interest.
5481*5552b385SBrandon 
5482*5552b385SBrandon   Output Parameters:
5483*5552b385SBrandon + edges    - Array of PetscGeom EDGE objects referenced by the PetscGeom FACE object
5484*5552b385SBrandon - numEdges - Number of EDGEs referenced by the PetscGeom FACE object. Also the size of **edges array.
5485*5552b385SBrandon 
5486*5552b385SBrandon   Level: intermediate
5487*5552b385SBrandon 
5488*5552b385SBrandon .seealso:
5489*5552b385SBrandon @*/
5490*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelFaceEdges(DM dm, PetscGeom body, PetscGeom face, PetscGeom **edges, PetscInt *numEdges)
5491*5552b385SBrandon {
5492*5552b385SBrandon   PetscFunctionBeginHot;
5493*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5494*5552b385SBrandon   PetscContainer modelObj;
5495*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5496*5552b385SBrandon 
5497*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5498*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5499*5552b385SBrandon   if (!modelObj) {
5500*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5501*5552b385SBrandon     islite = PETSC_TRUE;
5502*5552b385SBrandon   }
5503*5552b385SBrandon 
5504*5552b385SBrandon   if (islite) {
5505*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, face, EDGE, numEdges, edges));
5506*5552b385SBrandon   } else {
5507*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, face, EDGE, numEdges, edges));
5508*5552b385SBrandon   }
5509*5552b385SBrandon   #endif
5510*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5511*5552b385SBrandon }
5512*5552b385SBrandon 
5513*5552b385SBrandon /*@C
5514*5552b385SBrandon   DMPlexGetGeomModelBodyEdges - Returns an array of PetscGeom EDGE objects attached to the referenced BODY geomtric entity as well as the number of EDGEs.
5515*5552b385SBrandon 
5516*5552b385SBrandon   Collective
5517*5552b385SBrandon 
5518*5552b385SBrandon   Input Parameters:
5519*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5520*5552b385SBrandon - body - PetscGeom body object of interest.
5521*5552b385SBrandon 
5522*5552b385SBrandon   Output Parameters:
5523*5552b385SBrandon + edges    - Array of PetscGeom EDGE objects referenced by the PetscGeom BODY object
5524*5552b385SBrandon - numEdges - Number of EDGEs referenced by the PetscGeom BODY object. Also the size of **edges array.
5525*5552b385SBrandon 
5526*5552b385SBrandon   Level: intermediate
5527*5552b385SBrandon 
5528*5552b385SBrandon .seealso:
5529*5552b385SBrandon @*/
5530*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelBodyEdges(DM dm, PetscGeom body, PetscGeom **edges, PetscInt *numEdges)
5531*5552b385SBrandon {
5532*5552b385SBrandon   PetscFunctionBeginHot;
5533*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5534*5552b385SBrandon   PetscContainer modelObj;
5535*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5536*5552b385SBrandon 
5537*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5538*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5539*5552b385SBrandon   if (!modelObj) {
5540*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5541*5552b385SBrandon     islite = PETSC_TRUE;
5542*5552b385SBrandon   }
5543*5552b385SBrandon 
5544*5552b385SBrandon   if (islite) {
5545*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, numEdges, edges));
5546*5552b385SBrandon   } else {
5547*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, EDGE, numEdges, edges));
5548*5552b385SBrandon   }
5549*5552b385SBrandon   #endif
5550*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5551*5552b385SBrandon }
5552*5552b385SBrandon 
5553*5552b385SBrandon /*@C
5554*5552b385SBrandon   DMPlexGetGeomModelBodyNodes - Returns an array of PetscGeom NODE objects attached to the referenced BODY geomtric entity as well as the number of NODES.
5555*5552b385SBrandon 
5556*5552b385SBrandon   Collective
5557*5552b385SBrandon 
5558*5552b385SBrandon   Input Parameters:
5559*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5560*5552b385SBrandon - body - PetscGeom body object of interest.
5561*5552b385SBrandon 
5562*5552b385SBrandon   Output Parameters:
5563*5552b385SBrandon + nodes    - Array of PetscGeom NODE objects referenced by the PetscGeom BODY object
5564*5552b385SBrandon - numNodes - Number of NODEs referenced by the PetscGeom BODY object. Also the size of **nodes array.
5565*5552b385SBrandon 
5566*5552b385SBrandon   Level: intermediate
5567*5552b385SBrandon 
5568*5552b385SBrandon .seealso:
5569*5552b385SBrandon @*/
5570*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelBodyNodes(DM dm, PetscGeom body, PetscGeom **nodes, PetscInt *numNodes)
5571*5552b385SBrandon {
5572*5552b385SBrandon   PetscFunctionBeginHot;
5573*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5574*5552b385SBrandon   PetscContainer modelObj;
5575*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5576*5552b385SBrandon 
5577*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5578*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5579*5552b385SBrandon   if (!modelObj) {
5580*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5581*5552b385SBrandon     islite = PETSC_TRUE;
5582*5552b385SBrandon   }
5583*5552b385SBrandon 
5584*5552b385SBrandon   if (islite) {
5585*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, NODE, numNodes, nodes));
5586*5552b385SBrandon   } else {
5587*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, NODE, numNodes, nodes));
5588*5552b385SBrandon   }
5589*5552b385SBrandon   #endif
5590*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5591*5552b385SBrandon }
5592*5552b385SBrandon 
5593*5552b385SBrandon /*@C
5594*5552b385SBrandon   DMPlexGetGeomModelEdgeNodes - Returns an array of PetscGeom NODE objects attached to the referenced EDGE geomtric entity as well as the number of NODES.
5595*5552b385SBrandon 
5596*5552b385SBrandon   Collective
5597*5552b385SBrandon 
5598*5552b385SBrandon   Input Parameters:
5599*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5600*5552b385SBrandon . body - PetscGeom body object containing the EDGE object of interest.
5601*5552b385SBrandon - edge - PetscGeom EDGE object with NODEs of interest.
5602*5552b385SBrandon 
5603*5552b385SBrandon   Output Parameters:
5604*5552b385SBrandon + nodes    - Array of PetscGeom NODE objects referenced by the PetscGeom EDGE object
5605*5552b385SBrandon - numNodes - Number of Nodes referenced by the PetscGeom EDGE object. Also the size of **nodes array.
5606*5552b385SBrandon 
5607*5552b385SBrandon   Level: intermediate
5608*5552b385SBrandon 
5609*5552b385SBrandon .seealso:
5610*5552b385SBrandon @*/
5611*5552b385SBrandon PetscErrorCode DMPlexGetGeomModelEdgeNodes(DM dm, PetscGeom body, PetscGeom edge, PetscGeom **nodes, PetscInt *numNodes)
5612*5552b385SBrandon {
5613*5552b385SBrandon   PetscFunctionBeginHot;
5614*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5615*5552b385SBrandon   PetscContainer modelObj;
5616*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5617*5552b385SBrandon 
5618*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5619*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5620*5552b385SBrandon   if (!modelObj) {
5621*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5622*5552b385SBrandon     islite = PETSC_TRUE;
5623*5552b385SBrandon   }
5624*5552b385SBrandon 
5625*5552b385SBrandon   if (islite) {
5626*5552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, edge, NODE, numNodes, nodes));
5627*5552b385SBrandon   } else {
5628*5552b385SBrandon     PetscCall(EG_getBodyTopos(body, edge, NODE, numNodes, nodes));
5629*5552b385SBrandon   }
5630*5552b385SBrandon   #endif
5631*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5632*5552b385SBrandon }
5633*5552b385SBrandon 
5634*5552b385SBrandon /*@C
5635*5552b385SBrandon   DMPlexGetGeomID - Returns ID number of the entity in the geometric (CAD) model
5636*5552b385SBrandon 
5637*5552b385SBrandon   Collective
5638*5552b385SBrandon 
5639*5552b385SBrandon   Input Parameters:
5640*5552b385SBrandon + dm      - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5641*5552b385SBrandon . body    - PetscGeom body object containing the lower level entity the ID number is being requested.
5642*5552b385SBrandon - topoObj - PetscGeom SHELL, FACE, LOOP, EDGE, or NODE object for which ID number is being requested.
56437bee2925SMatthew Knepley 
56447bee2925SMatthew Knepley   Output Parameter:
5645*5552b385SBrandon . id - ID number of the entity
56467bee2925SMatthew Knepley 
5647*5552b385SBrandon   Level: intermediate
56487bee2925SMatthew Knepley 
5649*5552b385SBrandon .seealso:
56507bee2925SMatthew Knepley @*/
5651*5552b385SBrandon PetscErrorCode DMPlexGetGeomID(DM dm, PetscGeom body, PetscGeom topoObj, PetscInt *id)
5652d71ae5a4SJacob Faibussowitsch {
5653*5552b385SBrandon   PetscFunctionBeginHot;
5654*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5655*5552b385SBrandon   PetscContainer modelObj;
5656*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5657*5552b385SBrandon   int            topoID;
5658*5552b385SBrandon 
5659*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5660*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5661*5552b385SBrandon   if (!modelObj) {
5662*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5663*5552b385SBrandon     islite = PETSC_TRUE;
5664*5552b385SBrandon   }
5665*5552b385SBrandon 
5666*5552b385SBrandon   // Get Topology Object's ID
5667*5552b385SBrandon   if (islite) {
5668*5552b385SBrandon     topoID = EGlite_indexBodyTopo(body, topoObj);
5669*5552b385SBrandon   } else {
5670*5552b385SBrandon     topoID = EG_indexBodyTopo(body, topoObj);
5671*5552b385SBrandon   }
5672*5552b385SBrandon 
5673*5552b385SBrandon   *id = topoID;
56747bee2925SMatthew Knepley   #endif
5675*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5676*5552b385SBrandon }
5677*5552b385SBrandon 
5678*5552b385SBrandon /*@C
5679*5552b385SBrandon   DMPlexGetGeomObject - Returns Geometry Object using the objects ID in the geometric (CAD) model
5680*5552b385SBrandon 
5681*5552b385SBrandon   Collective
5682*5552b385SBrandon 
5683*5552b385SBrandon   Input Parameters:
5684*5552b385SBrandon + dm       - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5685*5552b385SBrandon . body     - PetscGeom body object containing the lower level entity the referenced by the ID.
5686*5552b385SBrandon . geomType - Keyword SHELL, FACE, LOOP, EDGE, or NODE of the geometry type for which ID number is being requested.
5687*5552b385SBrandon - geomID   - ID number of the geometry entity being requested.
5688*5552b385SBrandon 
5689*5552b385SBrandon   Output Parameter:
5690*5552b385SBrandon . geomObj - Geometry Object referenced by the ID number requested.
5691*5552b385SBrandon 
5692*5552b385SBrandon   Level: intermediate
5693*5552b385SBrandon 
5694*5552b385SBrandon .seealso:
5695*5552b385SBrandon @*/
5696*5552b385SBrandon PetscErrorCode DMPlexGetGeomObject(DM dm, PetscGeom body, PetscInt geomType, PetscInt geomID, PetscGeom *geomObj)
5697*5552b385SBrandon {
5698*5552b385SBrandon   PetscFunctionBeginHot;
5699*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5700*5552b385SBrandon   PetscContainer modelObj;
5701*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5702*5552b385SBrandon 
5703*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5704*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5705*5552b385SBrandon   if (!modelObj) {
5706*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5707*5552b385SBrandon     islite = PETSC_TRUE;
5708*5552b385SBrandon   }
5709*5552b385SBrandon 
5710*5552b385SBrandon   // Get Topology Object's ID
5711*5552b385SBrandon   if (islite) {
5712*5552b385SBrandon     PetscCall(EGlite_objectBodyTopo(body, geomType, geomID, geomObj));
5713*5552b385SBrandon   } else {
5714*5552b385SBrandon     PetscCall(EG_objectBodyTopo(body, geomType, geomID, geomObj));
5715*5552b385SBrandon   }
5716*5552b385SBrandon   #endif
5717*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5718*5552b385SBrandon }
5719*5552b385SBrandon 
5720*5552b385SBrandon /*@C
5721*5552b385SBrandon   DMPlexGetGeomFaceNumOfControlPoints - Returns the total number of Control Points (and associated Weights) defining a FACE of a Geometry
5722*5552b385SBrandon 
5723*5552b385SBrandon   Not collective
5724*5552b385SBrandon 
5725*5552b385SBrandon   Input Parameters:
5726*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5727*5552b385SBrandon - face - PetscGeom FACE object
5728*5552b385SBrandon 
5729*5552b385SBrandon   Output Parameter:
5730*5552b385SBrandon . numCntrlPnts - Number of Control Points (and Weights) defining the FACE
5731*5552b385SBrandon 
5732*5552b385SBrandon   Level: intermediate
5733*5552b385SBrandon 
5734*5552b385SBrandon .seealso:
5735*5552b385SBrandon @*/
5736*5552b385SBrandon PetscErrorCode DMPlexGetGeomFaceNumOfControlPoints(DM dm, PetscGeom face, PetscInt *numCntrlPnts)
5737*5552b385SBrandon {
5738*5552b385SBrandon   PetscFunctionBeginHot;
5739*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5740*5552b385SBrandon   PetscContainer modelObj;
5741*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5742*5552b385SBrandon   PetscGeom      geom, gRef;
5743*5552b385SBrandon   PetscGeom     *lobjs;
5744*5552b385SBrandon   int            Nl, oclass, mtype, goclass, gmtype;
5745*5552b385SBrandon   int           *lsenses, *gpinfo;
5746*5552b385SBrandon   double        *gprv;
5747*5552b385SBrandon 
5748*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5749*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5750*5552b385SBrandon   if (!modelObj) {
5751*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5752*5552b385SBrandon     islite = PETSC_TRUE;
5753*5552b385SBrandon   }
5754*5552b385SBrandon 
5755*5552b385SBrandon   // Get Total Number of Control Points on FACE
5756*5552b385SBrandon   if (islite) {
5757*5552b385SBrandon     PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
5758*5552b385SBrandon     PetscCall(EGlite_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
5759*5552b385SBrandon   } else {
5760*5552b385SBrandon     PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
5761*5552b385SBrandon     PetscCall(EG_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
5762*5552b385SBrandon   }
5763*5552b385SBrandon 
5764*5552b385SBrandon   *numCntrlPnts = gpinfo[2] * gpinfo[5];
5765*5552b385SBrandon   #endif
5766*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5767*5552b385SBrandon }
5768*5552b385SBrandon 
5769*5552b385SBrandon /*@C
5770*5552b385SBrandon   DMPlexGetGeomBodyMassProperties - Returns the Volume, Surface Area, Center of Gravity, and Inertia about the Body's Center of Gravity
5771*5552b385SBrandon 
5772*5552b385SBrandon   Not collective
5773*5552b385SBrandon 
5774*5552b385SBrandon   Input Parameters:
5775*5552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5776*5552b385SBrandon - body - PetscGeom BODY object
5777*5552b385SBrandon 
5778*5552b385SBrandon   Output Parameters:
5779*5552b385SBrandon + volume           - Volume of the CAD Body attached to the DM Plex
5780*5552b385SBrandon . surfArea         - Surface Area of the CAD Body attached to the DM Plex
5781*5552b385SBrandon . centerOfGravity  - Array with the Center of Gravity coordinates of the CAD Body attached to the DM Plex [x, y, z]
5782*5552b385SBrandon . COGszie          - Size of centerOfGravity[] Array
5783*5552b385SBrandon . inertiaMatrixCOG - Array containing the Inertia about the Body's Center of Gravity [Ixx, Ixy, Ixz, Iyx, Iyy, Iyz, Izx, Izy, Izz]
5784*5552b385SBrandon - IMCOGsize        - Size of inertiaMatrixCOG[] Array
5785*5552b385SBrandon 
5786*5552b385SBrandon   Level: intermediate
5787*5552b385SBrandon 
5788*5552b385SBrandon .seealso:
5789*5552b385SBrandon @*/
5790*5552b385SBrandon PetscErrorCode DMPlexGetGeomBodyMassProperties(DM dm, PetscGeom body, PetscScalar *volume, PetscScalar *surfArea, PetscScalar **centerOfGravity, PetscInt *COGsize, PetscScalar **inertiaMatrixCOG, PetscInt *IMCOGsize)
5791*5552b385SBrandon {
5792*5552b385SBrandon   PetscFunctionBeginHot;
5793*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5794*5552b385SBrandon   PetscContainer modelObj;
5795*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5796*5552b385SBrandon   PetscScalar    geomData[14];
5797*5552b385SBrandon 
5798*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5799*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5800*5552b385SBrandon   if (!modelObj) {
5801*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5802*5552b385SBrandon     islite = PETSC_TRUE;
5803*5552b385SBrandon     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");
5804*5552b385SBrandon   }
5805*5552b385SBrandon 
5806*5552b385SBrandon   if (islite) {
5807*5552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, " WARNING!! This functionality is not supported for EGADSlite files. \n"));
5808*5552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, " All returned values are equal to 0 \n"));
5809*5552b385SBrandon   } else {
5810*5552b385SBrandon     PetscCall(EG_getMassProperties(body, geomData));
5811*5552b385SBrandon   }
5812*5552b385SBrandon 
5813*5552b385SBrandon   PetscCall(PetscMalloc2(3, centerOfGravity, 9, inertiaMatrixCOG));
5814*5552b385SBrandon 
5815*5552b385SBrandon   if (!islite) {
5816*5552b385SBrandon     *volume   = geomData[0];
5817*5552b385SBrandon     *surfArea = geomData[1];
5818*5552b385SBrandon     for (int ii = 2; ii < 5; ++ii) { (*centerOfGravity)[ii - 2] = geomData[ii]; }
5819*5552b385SBrandon     *COGsize = 3;
5820*5552b385SBrandon     for (int ii = 5; ii < 14; ++ii) { (*inertiaMatrixCOG)[ii - 5] = geomData[ii]; }
5821*5552b385SBrandon     *IMCOGsize = 9;
5822*5552b385SBrandon   } else {
5823*5552b385SBrandon     *volume   = 0.;
5824*5552b385SBrandon     *surfArea = 0.;
5825*5552b385SBrandon     for (int ii = 2; ii < 5; ++ii) { (*centerOfGravity)[ii - 2] = 0.; }
5826*5552b385SBrandon     *COGsize = 0;
5827*5552b385SBrandon     for (int ii = 5; ii < 14; ++ii) { (*inertiaMatrixCOG)[ii - 5] = 0.; }
5828*5552b385SBrandon     *IMCOGsize = 0;
5829*5552b385SBrandon   }
5830*5552b385SBrandon   #endif
5831*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5832*5552b385SBrandon }
5833*5552b385SBrandon 
5834*5552b385SBrandon PetscErrorCode DMPlexRestoreGeomBodyMassProperties(DM dm, PetscGeom body, PetscScalar *volume, PetscScalar *surfArea, PetscScalar **centerOfGravity, PetscInt *COGsize, PetscScalar **inertiaMatrixCOG, PetscInt *IMCOGsize)
5835*5552b385SBrandon {
5836*5552b385SBrandon   PetscFunctionBegin;
5837*5552b385SBrandon   PetscCall(PetscFree2(*centerOfGravity, *inertiaMatrixCOG));
5838*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5839*5552b385SBrandon }
5840*5552b385SBrandon 
5841*5552b385SBrandon /*@C
5842*5552b385SBrandon   DMPlexFreeGeomObject - Frees PetscGeom Objects
5843*5552b385SBrandon 
5844*5552b385SBrandon   Not collective
5845*5552b385SBrandon 
5846*5552b385SBrandon   Input Parameters:
5847*5552b385SBrandon + dm      - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5848*5552b385SBrandon - geomObj - PetscGeom object
5849*5552b385SBrandon 
5850*5552b385SBrandon   Level: intermediate
5851*5552b385SBrandon 
5852*5552b385SBrandon .seealso:
5853*5552b385SBrandon @*/
5854*5552b385SBrandon PetscErrorCode DMPlexFreeGeomObject(DM dm, PetscGeom *geomObj)
5855*5552b385SBrandon {
5856*5552b385SBrandon   PetscFunctionBeginHot;
5857*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
5858*5552b385SBrandon   PetscContainer modelObj;
5859*5552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5860*5552b385SBrandon 
5861*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5862*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5863*5552b385SBrandon   if (!modelObj) {
5864*5552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5865*5552b385SBrandon     islite = PETSC_TRUE;
5866*5552b385SBrandon   }
5867*5552b385SBrandon 
5868*5552b385SBrandon   if (islite) {
5869*5552b385SBrandon     EGlite_free(geomObj);
5870*5552b385SBrandon   } else {
5871*5552b385SBrandon     EG_free(geomObj);
5872*5552b385SBrandon   }
5873*5552b385SBrandon   #endif
5874*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5875*5552b385SBrandon }
5876*5552b385SBrandon 
5877*5552b385SBrandon /*@C
5878*5552b385SBrandon   DMPlexGetGeomCntrlPntAndWeightData - Gets Control Point and Associated Weight Data for the Geometry attached to the DMPlex
5879*5552b385SBrandon 
5880*5552b385SBrandon   Not collective
5881*5552b385SBrandon 
5882*5552b385SBrandon   Input Parameter:
5883*5552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5884*5552b385SBrandon 
5885*5552b385SBrandon   Output Parameters:
5886*5552b385SBrandon + cpHashTable       - Hash Table containing the relationship between FACE ID and Control Point IDs.
5887*5552b385SBrandon . cpCoordDataLength - Length of cpCoordData Array.
5888*5552b385SBrandon . cpCoordData       - Array holding the Geometry Control Point Coordinate Data.
5889*5552b385SBrandon . maxNumEquiv       - Maximum Number of Equivalent Control Points (Control Points with the same coordinates but different IDs).
5890*5552b385SBrandon . 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
5891*5552b385SBrandon . wHashTable        - Hash Table containing the relationship between FACE ID and Control Point Weight.
5892*5552b385SBrandon . wDataLength       - Length of wData Array.
5893*5552b385SBrandon - wData             - Array holding the Weight for an associated Geometry Control Point.
5894*5552b385SBrandon 
5895*5552b385SBrandon   Note:
5896*5552b385SBrandon   Must Call DMPLexGeomDataAndGrads() before calling this function.
5897*5552b385SBrandon 
5898*5552b385SBrandon   Level: intermediate
5899*5552b385SBrandon 
5900*5552b385SBrandon .seealso:
5901*5552b385SBrandon @*/
5902*5552b385SBrandon PetscErrorCode DMPlexGetGeomCntrlPntAndWeightData(DM dm, PetscHMapI *cpHashTable, PetscInt *cpCoordDataLength, PetscScalar **cpCoordData, PetscInt *maxNumEquiv, Mat *cpEquiv, PetscHMapI *wHashTable, PetscInt *wDataLength, PetscScalar **wData)
5903*5552b385SBrandon {
5904*5552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj, cpCoordDataLengthObj, wDataLengthObj, maxNumRelateObj;
5905*5552b385SBrandon   Vec            cntrlPtCoordsVec, cntrlPtWeightsVec;
5906*5552b385SBrandon   PetscInt      *cpCoordDataLengthPtr, *wDataLengthPtr, *maxNumEquivPtr;
5907*5552b385SBrandon   PetscHMapI     cpHashTableTemp, wHashTableTemp;
5908*5552b385SBrandon 
5909*5552b385SBrandon   PetscFunctionBeginHot;
5910*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5911*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5912*5552b385SBrandon   if (!modelObj) { PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj)); }
5913*5552b385SBrandon 
5914*5552b385SBrandon   if (!modelObj) { PetscFunctionReturn(PETSC_SUCCESS); }
5915*5552b385SBrandon 
5916*5552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
5917*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
5918*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
5919*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordDataLengthObj));
5920*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
5921*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
5922*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
5923*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Equivalancy Matrix", (PetscObject *)cpEquiv));
5924*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject *)&maxNumRelateObj));
5925*5552b385SBrandon 
5926*5552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
5927*5552b385SBrandon   PetscCall(PetscContainerGetPointer(cpHashTableObj, (void **)&cpHashTableTemp));
5928*5552b385SBrandon   PetscCall(PetscContainerGetPointer(cpCoordDataLengthObj, (void **)&cpCoordDataLengthPtr));
5929*5552b385SBrandon   PetscCall(PetscContainerGetPointer(wHashTableObj, (void **)&wHashTableTemp));
5930*5552b385SBrandon   PetscCall(PetscContainerGetPointer(wDataLengthObj, (void **)&wDataLengthPtr));
5931*5552b385SBrandon   PetscCall(PetscContainerGetPointer(maxNumRelateObj, (void **)&maxNumEquivPtr));
5932*5552b385SBrandon 
5933*5552b385SBrandon   *cpCoordDataLength = *cpCoordDataLengthPtr;
5934*5552b385SBrandon   *wDataLength       = *wDataLengthPtr;
5935*5552b385SBrandon   *maxNumEquiv       = *maxNumEquivPtr;
5936*5552b385SBrandon   *cpHashTable       = cpHashTableTemp;
5937*5552b385SBrandon   *wHashTable        = wHashTableTemp;
5938*5552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, cpCoordData));
5939*5552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, wData));
5940*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5941*5552b385SBrandon }
5942*5552b385SBrandon 
5943*5552b385SBrandon PetscErrorCode DMPlexRestoreGeomCntrlPntAndWeightData(DM dm, PetscHMapI *cpHashTable, PetscInt *cpCoordDataLength, PetscScalar **cpCoordData, PetscInt *maxNumEquiv, Mat *cpEquiv, PetscHMapI *wHashTable, PetscInt *wDataLength, PetscScalar **wData)
5944*5552b385SBrandon {
5945*5552b385SBrandon   Vec cntrlPtCoordsVec, cntrlPtWeightsVec;
5946*5552b385SBrandon 
5947*5552b385SBrandon   PetscFunctionBeginHot;
5948*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
5949*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, cpCoordData));
5950*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
5951*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, wData));
5952*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
5953*5552b385SBrandon }
5954*5552b385SBrandon 
5955*5552b385SBrandon /*@C
5956*5552b385SBrandon   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 .
5957*5552b385SBrandon 
5958*5552b385SBrandon   Not collective
5959*5552b385SBrandon 
5960*5552b385SBrandon   Input Parameter:
5961*5552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
5962*5552b385SBrandon 
5963*5552b385SBrandon   Output Parameters:
5964*5552b385SBrandon + cpSurfGradHashTable - Hash Table Relating the Control Point ID to the the Row in the cpSurfGrad Matrix
5965*5552b385SBrandon . 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.
5966*5552b385SBrandon . cpArraySize         - The size of arrays gradSACP and gradVolCP and is equal to 3 * total number of Control Points in the Geometry
5967*5552b385SBrandon . 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.
5968*5552b385SBrandon . gradVolCP           - Array contianing the Volume Gradient with respect to Control Point Data. Data is arranged by Control Point ID * 3 where 3 is for the coordinate dimension.
5969*5552b385SBrandon . wArraySize          - The size of arrayws gradSAW and gradVolW and is equal to the total number of Control Points in the Geometry.
5970*5552b385SBrandon . gradSAW             - Array containing the Surface Area Gradient with respect to Control Point Weight. Data is arranged by Control Point ID.
5971*5552b385SBrandon - gradVolW            - Array containing the Volume Gradient with respect to Control Point Weight. Data is arranged by Control Point ID.
5972*5552b385SBrandon 
5973*5552b385SBrandon   Notes:
5974*5552b385SBrandon   Must Call DMPLexGeomDataAndGrads() before calling this function.
5975*5552b385SBrandon 
5976*5552b385SBrandon   gradVolCP and gradVolW are only available when DMPlexGeomDataAndGrads() is called with fullGeomGrad = PETSC_TRUE.
5977*5552b385SBrandon 
5978*5552b385SBrandon   Level: intermediate
5979*5552b385SBrandon 
5980*5552b385SBrandon .seealso: DMPlexGeomDataAndGrads
5981*5552b385SBrandon @*/
5982*5552b385SBrandon PetscErrorCode DMPlexGetGeomGradData(DM dm, PetscHMapI *cpSurfGradHashTable, Mat *cpSurfGrad, PetscInt *cpArraySize, PetscScalar **gradSACP, PetscScalar **gradVolCP, PetscInt *wArraySize, PetscScalar **gradSAW, PetscScalar **gradVolW)
5983*5552b385SBrandon {
5984*5552b385SBrandon   PetscContainer modelObj, cpSurfGradHashTableObj, cpArraySizeObj, wArraySizeObj;
5985*5552b385SBrandon   Vec            gradSACPVec, gradVolCPVec, gradSAWVec, gradVolWVec;
5986*5552b385SBrandon   PetscInt      *cpArraySizePtr, *wArraySizePtr;
5987*5552b385SBrandon   PetscHMapI     cpSurfGradHashTableTemp;
5988*5552b385SBrandon 
5989*5552b385SBrandon   PetscFunctionBeginHot;
5990*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
5991*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5992*5552b385SBrandon   if (!modelObj) { PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj)); }
5993*5552b385SBrandon 
5994*5552b385SBrandon   if (!modelObj) { PetscFunctionReturn(PETSC_SUCCESS); }
5995*5552b385SBrandon 
5996*5552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
5997*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject *)&cpSurfGradHashTableObj));
5998*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Matrix", (PetscObject *)cpSurfGrad));
5999*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpArraySizeObj));
6000*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject *)&gradSACPVec));
6001*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Control Point Gradient", (PetscObject *)&gradVolCPVec));
6002*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wArraySizeObj));
6003*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject *)&gradSAWVec));
6004*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Weights Gradient", (PetscObject *)&gradVolWVec));
6005*5552b385SBrandon 
6006*5552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
6007*5552b385SBrandon   if (cpSurfGradHashTableObj) {
6008*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cpSurfGradHashTableObj, (void **)&cpSurfGradHashTableTemp));
6009*5552b385SBrandon     *cpSurfGradHashTable = cpSurfGradHashTableTemp;
6010*5552b385SBrandon   }
6011*5552b385SBrandon 
6012*5552b385SBrandon   if (cpArraySizeObj) {
6013*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cpArraySizeObj, (void **)&cpArraySizePtr));
6014*5552b385SBrandon     *cpArraySize = *cpArraySizePtr;
6015*5552b385SBrandon   }
6016*5552b385SBrandon 
6017*5552b385SBrandon   if (gradSACPVec) PetscCall(VecGetArrayWrite(gradSACPVec, gradSACP));
6018*5552b385SBrandon   if (gradVolCPVec) PetscCall(VecGetArrayWrite(gradVolCPVec, gradVolCP));
6019*5552b385SBrandon   if (gradSAWVec) PetscCall(VecGetArrayWrite(gradSAWVec, gradSAW));
6020*5552b385SBrandon   if (gradVolWVec) PetscCall(VecGetArrayWrite(gradVolWVec, gradVolW));
6021*5552b385SBrandon 
6022*5552b385SBrandon   if (wArraySizeObj) {
6023*5552b385SBrandon     PetscCall(PetscContainerGetPointer(wArraySizeObj, (void **)&wArraySizePtr));
6024*5552b385SBrandon     *wArraySize = *wArraySizePtr;
6025*5552b385SBrandon   }
6026*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
6027*5552b385SBrandon }
6028*5552b385SBrandon 
6029*5552b385SBrandon PetscErrorCode DMPlexRestoreGeomGradData(DM dm, PetscHMapI *cpSurfGradHashTable, Mat *cpSurfGrad, PetscInt *cpArraySize, PetscScalar **gradSACP, PetscScalar **gradVolCP, PetscInt *wArraySize, PetscScalar **gradSAW, PetscScalar **gradVolW)
6030*5552b385SBrandon {
6031*5552b385SBrandon   Vec gradSACPVec, gradVolCPVec, gradSAWVec, gradVolWVec;
60327bee2925SMatthew Knepley 
60337bee2925SMatthew Knepley   PetscFunctionBegin;
6034*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject *)&gradSACPVec));
6035*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Control Point Gradient", (PetscObject *)&gradVolCPVec));
6036*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject *)&gradSAWVec));
6037*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Weights Gradient", (PetscObject *)&gradVolWVec));
6038*5552b385SBrandon 
6039*5552b385SBrandon   if (gradSACPVec) PetscCall(VecRestoreArrayWrite(gradSACPVec, gradSACP));
6040*5552b385SBrandon   if (gradVolCPVec) PetscCall(VecRestoreArrayWrite(gradVolCPVec, gradVolCP));
6041*5552b385SBrandon   if (gradSAWVec) PetscCall(VecRestoreArrayWrite(gradSAWVec, gradSAW));
6042*5552b385SBrandon   if (gradVolWVec) PetscCall(VecRestoreArrayWrite(gradVolWVec, gradVolW));
60433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60447bee2925SMatthew Knepley }
6045*5552b385SBrandon 
6046*5552b385SBrandon /*@C
6047*5552b385SBrandon   DMPlexGetGeomCntrlPntMaps - Gets arrays which maps Control Point IDs to their associated Geometry FACE, EDGE, and VERTEX.
6048*5552b385SBrandon 
6049*5552b385SBrandon   Not collective
6050*5552b385SBrandon 
6051*5552b385SBrandon   Input Parameter:
6052*5552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
6053*5552b385SBrandon 
6054*5552b385SBrandon   Output Parameters:
6055*5552b385SBrandon + numCntrlPnts            - Number of Control Points defining the Geometry attached to the DMPlex
6056*5552b385SBrandon . cntrlPntFaceMap         - Array containing the FACE ID for the Control Point. Array index corresponds to Control Point ID.
6057*5552b385SBrandon . cntrlPntWeightFaceMap   - Array containing the FACE ID for the Control Point Weight. Array index corresponds to Control Point ID.
6058*5552b385SBrandon . cntrlPntEdgeMap         - Array containing the EDGE ID for the Control Point. Array index corresponds to Control Point ID.
6059*5552b385SBrandon . cntrlPntWeightEdgeMap   - Array containing the EDGE ID for the Control Point Weight. Array index corresponds to Control Point ID.
6060*5552b385SBrandon . cntrlPntVertexMap       - Array containing the VERTEX ID for the Control Point. Array index corresponds to Control Point ID.
6061*5552b385SBrandon - cntrlPntWeightVertexMap - Array containing the VERTEX ID for the Control Point Weight. Array index corresponds to Control Point ID.
6062*5552b385SBrandon 
6063*5552b385SBrandon   Note:
6064*5552b385SBrandon   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.
6065*5552b385SBrandon 
6066*5552b385SBrandon   Level: intermediate
6067*5552b385SBrandon 
6068*5552b385SBrandon .seealso: DMPlexGeomDataAndGrads
6069*5552b385SBrandon @*/
6070*5552b385SBrandon PetscErrorCode DMPlexGetGeomCntrlPntMaps(DM dm, PetscInt *numCntrlPnts, PetscInt **cntrlPntFaceMap, PetscInt **cntrlPntWeightFaceMap, PetscInt **cntrlPntEdgeMap, PetscInt **cntrlPntWeightEdgeMap, PetscInt **cntrlPntVertexMap, PetscInt **cntrlPntWeightVertexMap)
6071*5552b385SBrandon {
6072*5552b385SBrandon   PetscFunctionBeginHot;
6073*5552b385SBrandon   #ifdef PETSC_HAVE_EGADS
6074*5552b385SBrandon   PetscContainer modelObj, numCntrlPntsObj, cntrlPntFaceMapObj, cntrlPntWeightFaceMapObj, cntrlPntEdgeMapObj, cntrlPntWeightEdgeMapObj, cntrlPntVertexMapObj, cntrlPntWeightVertexMapObj;
6075*5552b385SBrandon   PetscInt      *numCntrlPntsPtr, *cntrlPntFaceMapPtr, *cntrlPntWeightFaceMapPtr, *cntrlPntEdgeMapPtr, *cntrlPntWeightEdgeMapPtr, *cntrlPntVertexMapPtr, *cntrlPntWeightVertexMapPtr;
6076*5552b385SBrandon 
6077*5552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
6078*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
6079*5552b385SBrandon   if (!modelObj) { PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj)); }
6080*5552b385SBrandon 
6081*5552b385SBrandon   if (!modelObj) { PetscFunctionReturn(PETSC_SUCCESS); }
6082*5552b385SBrandon 
6083*5552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
6084*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&numCntrlPntsObj));
6085*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Face Map", (PetscObject *)&cntrlPntFaceMapObj));
6086*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject *)&cntrlPntWeightFaceMapObj));
6087*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Edge Map", (PetscObject *)&cntrlPntEdgeMapObj));
6088*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject *)&cntrlPntWeightEdgeMapObj));
6089*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Vertex Map", (PetscObject *)&cntrlPntVertexMapObj));
6090*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject *)&cntrlPntWeightVertexMapObj));
6091*5552b385SBrandon 
6092*5552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
6093*5552b385SBrandon   if (numCntrlPntsObj) {
6094*5552b385SBrandon     PetscCall(PetscContainerGetPointer(numCntrlPntsObj, (void **)&numCntrlPntsPtr));
6095*5552b385SBrandon     *numCntrlPnts = *numCntrlPntsPtr;
6096*5552b385SBrandon   }
6097*5552b385SBrandon 
6098*5552b385SBrandon   if (cntrlPntFaceMapObj) {
6099*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntFaceMapObj, (void **)&cntrlPntFaceMapPtr));
6100*5552b385SBrandon     *cntrlPntFaceMap = cntrlPntFaceMapPtr;
6101*5552b385SBrandon   }
6102*5552b385SBrandon 
6103*5552b385SBrandon   if (cntrlPntWeightFaceMapObj) {
6104*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntWeightFaceMapObj, (void **)&cntrlPntWeightFaceMapPtr));
6105*5552b385SBrandon     *cntrlPntWeightFaceMap = cntrlPntWeightFaceMapPtr;
6106*5552b385SBrandon   }
6107*5552b385SBrandon 
6108*5552b385SBrandon   if (cntrlPntEdgeMapObj) {
6109*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntEdgeMapObj, (void **)&cntrlPntEdgeMapPtr));
6110*5552b385SBrandon     *cntrlPntEdgeMap = cntrlPntEdgeMapPtr;
6111*5552b385SBrandon   }
6112*5552b385SBrandon 
6113*5552b385SBrandon   if (cntrlPntWeightEdgeMapObj) {
6114*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntWeightEdgeMapObj, (void **)&cntrlPntWeightEdgeMapPtr));
6115*5552b385SBrandon     *cntrlPntWeightEdgeMap = cntrlPntWeightEdgeMapPtr;
6116*5552b385SBrandon   }
6117*5552b385SBrandon 
6118*5552b385SBrandon   if (cntrlPntVertexMapObj) {
6119*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntVertexMapObj, (void **)&cntrlPntVertexMapPtr));
6120*5552b385SBrandon     *cntrlPntVertexMap = cntrlPntVertexMapPtr;
6121*5552b385SBrandon   }
6122*5552b385SBrandon 
6123*5552b385SBrandon   if (cntrlPntWeightVertexMapObj) {
6124*5552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntWeightVertexMapObj, (void **)&cntrlPntWeightVertexMapPtr));
6125*5552b385SBrandon     *cntrlPntWeightVertexMap = cntrlPntWeightVertexMapPtr;
6126*5552b385SBrandon   }
6127*5552b385SBrandon 
6128*5552b385SBrandon   #endif
6129*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
6130*5552b385SBrandon }
6131*5552b385SBrandon 
6132*5552b385SBrandon #endif
6133