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