Actual source code: plexsubmesh.c
1: #include <petsc/private/dmpleximpl.h>
2: #include <petsc/private/dmlabelimpl.h>
3: #include <petscsf.h>
5: static PetscErrorCode DMPlexCellIsHybrid_Internal(DM dm, PetscInt p, PetscBool *isHybrid)
6: {
7: DMPolytopeType ct;
9: PetscFunctionBegin;
10: PetscCall(DMPlexGetCellType(dm, p, &ct));
11: switch (ct) {
12: case DM_POLYTOPE_POINT_PRISM_TENSOR:
13: case DM_POLYTOPE_SEG_PRISM_TENSOR:
14: case DM_POLYTOPE_TRI_PRISM_TENSOR:
15: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
16: *isHybrid = PETSC_TRUE;
17: break;
18: default:
19: *isHybrid = PETSC_FALSE;
20: break;
21: }
22: PetscFunctionReturn(PETSC_SUCCESS);
23: }
25: static PetscErrorCode DMPlexGetTensorPrismBounds_Internal(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
26: {
27: DMLabel ctLabel;
29: PetscFunctionBegin;
30: if (cStart) *cStart = -1;
31: if (cEnd) *cEnd = -1;
32: PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
33: switch (dim) {
34: case 1:
35: PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_POINT_PRISM_TENSOR, cStart, cEnd));
36: break;
37: case 2:
38: PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_SEG_PRISM_TENSOR, cStart, cEnd));
39: break;
40: case 3:
41: PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_TRI_PRISM_TENSOR, cStart, cEnd));
42: if (*cStart < 0) PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_QUAD_PRISM_TENSOR, cStart, cEnd));
43: break;
44: default:
45: PetscFunctionReturn(PETSC_SUCCESS);
46: }
47: PetscFunctionReturn(PETSC_SUCCESS);
48: }
50: static PetscErrorCode DMPlexMarkBoundaryFaces_Internal(DM dm, PetscInt val, PetscInt cellHeight, DMLabel label)
51: {
52: PetscSF sf;
53: const PetscInt *rootdegree, *leaves;
54: PetscInt overlap, Nr = -1, Nl, pStart, fStart, fEnd;
56: PetscFunctionBegin;
57: PetscCall(DMGetPointSF(dm, &sf));
58: PetscCall(DMPlexGetOverlap(dm, &overlap));
59: if (sf && !overlap) PetscCall(PetscSFGetGraph(sf, &Nr, &Nl, &leaves, NULL));
60: if (Nr > 0) {
61: PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
62: PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
63: } else rootdegree = NULL;
64: PetscCall(DMPlexGetChart(dm, &pStart, NULL));
65: PetscCall(DMPlexGetHeightStratum(dm, cellHeight + 1, &fStart, &fEnd));
66: for (PetscInt f = fStart; f < fEnd; ++f) {
67: PetscInt supportSize, loc = -1;
69: PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
70: if (supportSize == 1) {
71: /* Do not mark faces which are shared, meaning
72: they are present in the pointSF, or
73: they have rootdegree > 0
74: since they presumably have cells on the other side */
75: if (Nr > 0) {
76: PetscCall(PetscFindInt(f, Nl, leaves, &loc));
77: if (rootdegree[f - pStart] || loc >= 0) continue;
78: }
79: if (val < 0) {
80: PetscInt *closure = NULL;
81: PetscInt clSize, cl, cval;
83: PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &clSize, &closure));
84: for (cl = 0; cl < clSize * 2; cl += 2) {
85: PetscCall(DMLabelGetValue(label, closure[cl], &cval));
86: if (cval < 0) continue;
87: PetscCall(DMLabelSetValue(label, f, cval));
88: break;
89: }
90: if (cl == clSize * 2) PetscCall(DMLabelSetValue(label, f, 1));
91: PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &clSize, &closure));
92: } else {
93: PetscCall(DMLabelSetValue(label, f, val));
94: }
95: }
96: }
97: PetscFunctionReturn(PETSC_SUCCESS);
98: }
100: /*@
101: DMPlexMarkBoundaryFaces - Mark all faces on the boundary
103: Not Collective
105: Input Parameters:
106: + dm - The original `DM`
107: - val - The marker value, or PETSC_DETERMINE to use some value in the closure (or 1 if none are found)
109: Output Parameter:
110: . label - The DMLabel marking boundary faces with the given value
112: Note:
113: This function will use the point `PetscSF` from the input `DM` to exclude points on the partition boundary from being marked, unless the partition overlap is greater than zero. If you also wish to mark the partition boundary, you can use `DMSetPointSF()` to temporarily set it to NULL, and then reset it to the original object after the call.
115: Level: developer
117: .seealso: `DMLabelCreate()`, `DMCreateLabel()`
118: @*/
119: PetscErrorCode DMPlexMarkBoundaryFaces(DM dm, PetscInt val, DMLabel label)
120: {
121: DMPlexInterpolatedFlag flg;
123: PetscFunctionBegin;
125: PetscCall(DMPlexIsInterpolated(dm, &flg));
126: PetscCheck(flg == DMPLEX_INTERPOLATED_FULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not fully interpolated on this rank");
127: PetscCall(DMPlexMarkBoundaryFaces_Internal(dm, val, 0, label));
128: PetscFunctionReturn(PETSC_SUCCESS);
129: }
131: static PetscErrorCode DMPlexLabelComplete_Internal(DM dm, DMLabel label, PetscBool completeCells)
132: {
133: IS valueIS;
134: PetscSF sfPoint;
135: const PetscInt *values;
136: PetscInt numValues, v, cStart, cEnd, nroots;
138: PetscFunctionBegin;
139: PetscCall(DMLabelGetNumValues(label, &numValues));
140: PetscCall(DMLabelGetValueIS(label, &valueIS));
141: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
142: PetscCall(ISGetIndices(valueIS, &values));
143: for (v = 0; v < numValues; ++v) {
144: IS pointIS;
145: const PetscInt *points;
146: PetscInt numPoints, p;
148: PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
149: PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
150: PetscCall(ISGetIndices(pointIS, &points));
151: for (p = 0; p < numPoints; ++p) {
152: PetscInt q = points[p];
153: PetscInt *closure = NULL;
154: PetscInt closureSize, c;
156: if (cStart <= q && q < cEnd && !completeCells) { /* skip cells */
157: continue;
158: }
159: PetscCall(DMPlexGetTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure));
160: for (c = 0; c < closureSize * 2; c += 2) PetscCall(DMLabelSetValue(label, closure[c], values[v]));
161: PetscCall(DMPlexRestoreTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure));
162: }
163: PetscCall(ISRestoreIndices(pointIS, &points));
164: PetscCall(ISDestroy(&pointIS));
165: }
166: PetscCall(ISRestoreIndices(valueIS, &values));
167: PetscCall(ISDestroy(&valueIS));
168: PetscCall(DMGetPointSF(dm, &sfPoint));
169: PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
170: if (nroots >= 0) {
171: DMLabel lblRoots, lblLeaves;
172: IS valueIS, pointIS;
173: const PetscInt *values;
174: PetscInt numValues, v;
176: /* Pull point contributions from remote leaves into local roots */
177: PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
178: PetscCall(DMLabelGetValueIS(lblLeaves, &valueIS));
179: PetscCall(ISGetLocalSize(valueIS, &numValues));
180: PetscCall(ISGetIndices(valueIS, &values));
181: for (v = 0; v < numValues; ++v) {
182: const PetscInt value = values[v];
184: PetscCall(DMLabelGetStratumIS(lblLeaves, value, &pointIS));
185: PetscCall(DMLabelInsertIS(label, pointIS, value));
186: PetscCall(ISDestroy(&pointIS));
187: }
188: PetscCall(ISRestoreIndices(valueIS, &values));
189: PetscCall(ISDestroy(&valueIS));
190: PetscCall(DMLabelDestroy(&lblLeaves));
191: /* Push point contributions from roots into remote leaves */
192: PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
193: PetscCall(DMLabelGetValueIS(lblRoots, &valueIS));
194: PetscCall(ISGetLocalSize(valueIS, &numValues));
195: PetscCall(ISGetIndices(valueIS, &values));
196: for (v = 0; v < numValues; ++v) {
197: const PetscInt value = values[v];
199: PetscCall(DMLabelGetStratumIS(lblRoots, value, &pointIS));
200: PetscCall(DMLabelInsertIS(label, pointIS, value));
201: PetscCall(ISDestroy(&pointIS));
202: }
203: PetscCall(ISRestoreIndices(valueIS, &values));
204: PetscCall(ISDestroy(&valueIS));
205: PetscCall(DMLabelDestroy(&lblRoots));
206: }
207: PetscFunctionReturn(PETSC_SUCCESS);
208: }
210: /*@
211: DMPlexLabelComplete - Starting with a label marking points on a surface, we add the transitive closure to the surface
213: Input Parameters:
214: + dm - The DM
215: - label - A DMLabel marking the surface points
217: Output Parameter:
218: . label - A DMLabel marking all surface points in the transitive closure
220: Level: developer
222: .seealso: `DMPlexLabelCohesiveComplete()`
223: @*/
224: PetscErrorCode DMPlexLabelComplete(DM dm, DMLabel label)
225: {
226: PetscFunctionBegin;
227: PetscCall(DMPlexLabelComplete_Internal(dm, label, PETSC_TRUE));
228: PetscFunctionReturn(PETSC_SUCCESS);
229: }
231: /*@
232: DMPlexLabelAddCells - Starting with a label marking points on a surface, we add a cell for each point
234: Input Parameters:
235: + dm - The DM
236: - label - A DMLabel marking the surface points
238: Output Parameter:
239: . label - A DMLabel incorporating cells
241: Level: developer
243: Note: The cells allow FEM boundary conditions to be applied using the cell geometry
245: .seealso: `DMPlexLabelAddFaceCells()`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`
246: @*/
247: PetscErrorCode DMPlexLabelAddCells(DM dm, DMLabel label)
248: {
249: IS valueIS;
250: const PetscInt *values;
251: PetscInt numValues, v, csStart, csEnd, chStart, chEnd;
253: PetscFunctionBegin;
254: PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &csStart, &csEnd));
255: PetscCall(DMPlexGetHeightStratum(dm, 0, &chStart, &chEnd));
256: PetscCall(DMLabelGetNumValues(label, &numValues));
257: PetscCall(DMLabelGetValueIS(label, &valueIS));
258: PetscCall(ISGetIndices(valueIS, &values));
259: for (v = 0; v < numValues; ++v) {
260: IS pointIS;
261: const PetscInt *points;
262: PetscInt numPoints, p;
264: PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
265: PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
266: PetscCall(ISGetIndices(pointIS, &points));
267: for (p = 0; p < numPoints; ++p) {
268: const PetscInt point = points[p];
269: PetscInt *closure = NULL;
270: PetscInt closureSize, cl, h, pStart, pEnd, cStart, cEnd;
272: // If the point is a hybrid, allow hybrid cells
273: PetscCall(DMPlexGetPointHeight(dm, point, &h));
274: PetscCall(DMPlexGetSimplexOrBoxCells(dm, h, &pStart, &pEnd));
275: if (point >= pStart && point < pEnd) {
276: cStart = csStart;
277: cEnd = csEnd;
278: } else {
279: cStart = chStart;
280: cEnd = chEnd;
281: }
283: PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure));
284: for (cl = closureSize - 1; cl > 0; --cl) {
285: const PetscInt cell = closure[cl * 2];
286: if ((cell >= cStart) && (cell < cEnd)) {
287: PetscCall(DMLabelSetValue(label, cell, values[v]));
288: break;
289: }
290: }
291: PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure));
292: }
293: PetscCall(ISRestoreIndices(pointIS, &points));
294: PetscCall(ISDestroy(&pointIS));
295: }
296: PetscCall(ISRestoreIndices(valueIS, &values));
297: PetscCall(ISDestroy(&valueIS));
298: PetscFunctionReturn(PETSC_SUCCESS);
299: }
301: /*@
302: DMPlexLabelAddFaceCells - Starting with a label marking faces on a surface, we add a cell for each face
304: Input Parameters:
305: + dm - The DM
306: - label - A DMLabel marking the surface points
308: Output Parameter:
309: . label - A DMLabel incorporating cells
311: Level: developer
313: Note: The cells allow FEM boundary conditions to be applied using the cell geometry
315: .seealso: `DMPlexLabelAddCells()`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`
316: @*/
317: PetscErrorCode DMPlexLabelAddFaceCells(DM dm, DMLabel label)
318: {
319: IS valueIS;
320: const PetscInt *values;
321: PetscInt numValues, v, cStart, cEnd, fStart, fEnd;
323: PetscFunctionBegin;
324: PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
325: PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
326: PetscCall(DMLabelGetNumValues(label, &numValues));
327: PetscCall(DMLabelGetValueIS(label, &valueIS));
328: PetscCall(ISGetIndices(valueIS, &values));
329: for (v = 0; v < numValues; ++v) {
330: IS pointIS;
331: const PetscInt *points;
332: PetscInt numPoints, p;
334: PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
335: PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
336: PetscCall(ISGetIndices(pointIS, &points));
337: for (p = 0; p < numPoints; ++p) {
338: const PetscInt face = points[p];
339: PetscInt *closure = NULL;
340: PetscInt closureSize, cl;
342: if ((face < fStart) || (face >= fEnd)) continue;
343: PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_FALSE, &closureSize, &closure));
344: for (cl = closureSize - 1; cl > 0; --cl) {
345: const PetscInt cell = closure[cl * 2];
346: if ((cell >= cStart) && (cell < cEnd)) {
347: PetscCall(DMLabelSetValue(label, cell, values[v]));
348: break;
349: }
350: }
351: PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_FALSE, &closureSize, &closure));
352: }
353: PetscCall(ISRestoreIndices(pointIS, &points));
354: PetscCall(ISDestroy(&pointIS));
355: }
356: PetscCall(ISRestoreIndices(valueIS, &values));
357: PetscCall(ISDestroy(&valueIS));
358: PetscFunctionReturn(PETSC_SUCCESS);
359: }
361: /*@
362: DMPlexLabelClearCells - Remove cells from a label
364: Input Parameters:
365: + dm - The DM
366: - label - A DMLabel marking surface points and their adjacent cells
368: Output Parameter:
369: . label - A DMLabel without cells
371: Level: developer
373: Note: This undoes DMPlexLabelAddCells() or DMPlexLabelAddFaceCells()
375: .seealso: `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`, `DMPlexLabelAddCells()`
376: @*/
377: PetscErrorCode DMPlexLabelClearCells(DM dm, DMLabel label)
378: {
379: IS valueIS;
380: const PetscInt *values;
381: PetscInt numValues, v, cStart, cEnd;
383: PetscFunctionBegin;
384: PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
385: PetscCall(DMLabelGetNumValues(label, &numValues));
386: PetscCall(DMLabelGetValueIS(label, &valueIS));
387: PetscCall(ISGetIndices(valueIS, &values));
388: for (v = 0; v < numValues; ++v) {
389: IS pointIS;
390: const PetscInt *points;
391: PetscInt numPoints, p;
393: PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
394: PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
395: PetscCall(ISGetIndices(pointIS, &points));
396: for (p = 0; p < numPoints; ++p) {
397: PetscInt point = points[p];
399: if (point >= cStart && point < cEnd) PetscCall(DMLabelClearValue(label, point, values[v]));
400: }
401: PetscCall(ISRestoreIndices(pointIS, &points));
402: PetscCall(ISDestroy(&pointIS));
403: }
404: PetscCall(ISRestoreIndices(valueIS, &values));
405: PetscCall(ISDestroy(&valueIS));
406: PetscFunctionReturn(PETSC_SUCCESS);
407: }
409: /* take (oldEnd, added) pairs, ordered by height and convert them to (oldstart, newstart) pairs, ordered by ascending
410: * index (skipping first, which is (0,0)) */
411: static inline PetscErrorCode DMPlexShiftPointSetUp_Internal(PetscInt depth, PetscInt depthShift[])
412: {
413: PetscInt d, off = 0;
415: PetscFunctionBegin;
416: /* sort by (oldend): yes this is an O(n^2) sort, we expect depth <= 3 */
417: for (d = 0; d < depth; d++) {
418: PetscInt firstd = d;
419: PetscInt firstStart = depthShift[2 * d];
420: PetscInt e;
422: for (e = d + 1; e <= depth; e++) {
423: if (depthShift[2 * e] < firstStart) {
424: firstd = e;
425: firstStart = depthShift[2 * d];
426: }
427: }
428: if (firstd != d) {
429: PetscInt swap[2];
431: e = firstd;
432: swap[0] = depthShift[2 * d];
433: swap[1] = depthShift[2 * d + 1];
434: depthShift[2 * d] = depthShift[2 * e];
435: depthShift[2 * d + 1] = depthShift[2 * e + 1];
436: depthShift[2 * e] = swap[0];
437: depthShift[2 * e + 1] = swap[1];
438: }
439: }
440: /* convert (oldstart, added) to (oldstart, newstart) */
441: for (d = 0; d <= depth; d++) {
442: off += depthShift[2 * d + 1];
443: depthShift[2 * d + 1] = depthShift[2 * d] + off;
444: }
445: PetscFunctionReturn(PETSC_SUCCESS);
446: }
448: /* depthShift is a list of (old, new) pairs */
449: static inline PetscInt DMPlexShiftPoint_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[])
450: {
451: PetscInt d;
452: PetscInt newOff = 0;
454: for (d = 0; d <= depth; d++) {
455: if (p < depthShift[2 * d]) return p + newOff;
456: else newOff = depthShift[2 * d + 1] - depthShift[2 * d];
457: }
458: return p + newOff;
459: }
461: /* depthShift is a list of (old, new) pairs */
462: static inline PetscInt DMPlexShiftPointInverse_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[])
463: {
464: PetscInt d;
465: PetscInt newOff = 0;
467: for (d = 0; d <= depth; d++) {
468: if (p < depthShift[2 * d + 1]) return p + newOff;
469: else newOff = depthShift[2 * d] - depthShift[2 * d + 1];
470: }
471: return p + newOff;
472: }
474: static PetscErrorCode DMPlexShiftSizes_Internal(DM dm, PetscInt depthShift[], DM dmNew)
475: {
476: PetscInt depth = 0, d, pStart, pEnd, p;
477: DMLabel depthLabel;
479: PetscFunctionBegin;
480: PetscCall(DMPlexGetDepth(dm, &depth));
481: if (depth < 0) PetscFunctionReturn(PETSC_SUCCESS);
482: /* Step 1: Expand chart */
483: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
484: pEnd = DMPlexShiftPoint_Internal(pEnd, depth, depthShift);
485: PetscCall(DMPlexSetChart(dmNew, pStart, pEnd));
486: PetscCall(DMCreateLabel(dmNew, "depth"));
487: PetscCall(DMPlexGetDepthLabel(dmNew, &depthLabel));
488: PetscCall(DMCreateLabel(dmNew, "celltype"));
489: /* Step 2: Set cone and support sizes */
490: for (d = 0; d <= depth; ++d) {
491: PetscInt pStartNew, pEndNew;
492: IS pIS;
494: PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
495: pStartNew = DMPlexShiftPoint_Internal(pStart, depth, depthShift);
496: pEndNew = DMPlexShiftPoint_Internal(pEnd, depth, depthShift);
497: PetscCall(ISCreateStride(PETSC_COMM_SELF, pEndNew - pStartNew, pStartNew, 1, &pIS));
498: PetscCall(DMLabelSetStratumIS(depthLabel, d, pIS));
499: PetscCall(ISDestroy(&pIS));
500: for (p = pStart; p < pEnd; ++p) {
501: PetscInt newp = DMPlexShiftPoint_Internal(p, depth, depthShift);
502: PetscInt size;
503: DMPolytopeType ct;
505: PetscCall(DMPlexGetConeSize(dm, p, &size));
506: PetscCall(DMPlexSetConeSize(dmNew, newp, size));
507: PetscCall(DMPlexGetSupportSize(dm, p, &size));
508: PetscCall(DMPlexSetSupportSize(dmNew, newp, size));
509: PetscCall(DMPlexGetCellType(dm, p, &ct));
510: PetscCall(DMPlexSetCellType(dmNew, newp, ct));
511: }
512: }
513: PetscFunctionReturn(PETSC_SUCCESS);
514: }
516: static PetscErrorCode DMPlexShiftPoints_Internal(DM dm, PetscInt depthShift[], DM dmNew)
517: {
518: PetscInt *newpoints;
519: PetscInt depth = 0, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, pStart, pEnd, p;
521: PetscFunctionBegin;
522: PetscCall(DMPlexGetDepth(dm, &depth));
523: if (depth < 0) PetscFunctionReturn(PETSC_SUCCESS);
524: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
525: PetscCall(DMPlexGetMaxSizes(dmNew, &maxConeSizeNew, &maxSupportSizeNew));
526: PetscCall(PetscMalloc1(PetscMax(PetscMax(maxConeSize, maxSupportSize), PetscMax(maxConeSizeNew, maxSupportSizeNew)), &newpoints));
527: /* Step 5: Set cones and supports */
528: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
529: for (p = pStart; p < pEnd; ++p) {
530: const PetscInt *points = NULL, *orientations = NULL;
531: PetscInt size, sizeNew, i, newp = DMPlexShiftPoint_Internal(p, depth, depthShift);
533: PetscCall(DMPlexGetConeSize(dm, p, &size));
534: PetscCall(DMPlexGetCone(dm, p, &points));
535: PetscCall(DMPlexGetConeOrientation(dm, p, &orientations));
536: for (i = 0; i < size; ++i) newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift);
537: PetscCall(DMPlexSetCone(dmNew, newp, newpoints));
538: PetscCall(DMPlexSetConeOrientation(dmNew, newp, orientations));
539: PetscCall(DMPlexGetSupportSize(dm, p, &size));
540: PetscCall(DMPlexGetSupportSize(dmNew, newp, &sizeNew));
541: PetscCall(DMPlexGetSupport(dm, p, &points));
542: for (i = 0; i < size; ++i) newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift);
543: for (i = size; i < sizeNew; ++i) newpoints[i] = 0;
544: PetscCall(DMPlexSetSupport(dmNew, newp, newpoints));
545: }
546: PetscCall(PetscFree(newpoints));
547: PetscFunctionReturn(PETSC_SUCCESS);
548: }
550: static PetscErrorCode DMPlexShiftCoordinates_Internal(DM dm, PetscInt depthShift[], DM dmNew)
551: {
552: PetscSection coordSection, newCoordSection;
553: Vec coordinates, newCoordinates;
554: PetscScalar *coords, *newCoords;
555: PetscInt coordSize, sStart, sEnd;
556: PetscInt dim, depth = 0, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v;
557: PetscBool hasCells;
559: PetscFunctionBegin;
560: PetscCall(DMGetCoordinateDim(dm, &dim));
561: PetscCall(DMSetCoordinateDim(dmNew, dim));
562: PetscCall(DMPlexGetDepth(dm, &depth));
563: /* Step 8: Convert coordinates */
564: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
565: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
566: PetscCall(DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew));
567: PetscCall(DMPlexGetHeightStratum(dmNew, 0, &cStartNew, &cEndNew));
568: PetscCall(DMGetCoordinateSection(dm, &coordSection));
569: PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection));
570: PetscCall(PetscSectionSetNumFields(newCoordSection, 1));
571: PetscCall(PetscSectionSetFieldComponents(newCoordSection, 0, dim));
572: PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd));
573: hasCells = sStart == cStart ? PETSC_TRUE : PETSC_FALSE;
574: PetscCall(PetscSectionSetChart(newCoordSection, hasCells ? cStartNew : vStartNew, vEndNew));
575: if (hasCells) {
576: for (c = cStart; c < cEnd; ++c) {
577: PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof;
579: PetscCall(PetscSectionGetDof(coordSection, c, &dof));
580: PetscCall(PetscSectionSetDof(newCoordSection, cNew, dof));
581: PetscCall(PetscSectionSetFieldDof(newCoordSection, cNew, 0, dof));
582: }
583: }
584: for (v = vStartNew; v < vEndNew; ++v) {
585: PetscCall(PetscSectionSetDof(newCoordSection, v, dim));
586: PetscCall(PetscSectionSetFieldDof(newCoordSection, v, 0, dim));
587: }
588: PetscCall(PetscSectionSetUp(newCoordSection));
589: PetscCall(DMSetCoordinateSection(dmNew, PETSC_DETERMINE, newCoordSection));
590: PetscCall(PetscSectionGetStorageSize(newCoordSection, &coordSize));
591: PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates));
592: PetscCall(PetscObjectSetName((PetscObject)newCoordinates, "coordinates"));
593: PetscCall(VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE));
594: PetscCall(VecSetBlockSize(newCoordinates, dim));
595: PetscCall(VecSetType(newCoordinates, VECSTANDARD));
596: PetscCall(DMSetCoordinatesLocal(dmNew, newCoordinates));
597: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
598: PetscCall(VecGetArray(coordinates, &coords));
599: PetscCall(VecGetArray(newCoordinates, &newCoords));
600: if (hasCells) {
601: for (c = cStart; c < cEnd; ++c) {
602: PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof, off, noff, d;
604: PetscCall(PetscSectionGetDof(coordSection, c, &dof));
605: PetscCall(PetscSectionGetOffset(coordSection, c, &off));
606: PetscCall(PetscSectionGetOffset(newCoordSection, cNew, &noff));
607: for (d = 0; d < dof; ++d) newCoords[noff + d] = coords[off + d];
608: }
609: }
610: for (v = vStart; v < vEnd; ++v) {
611: PetscInt dof, off, noff, d;
613: PetscCall(PetscSectionGetDof(coordSection, v, &dof));
614: PetscCall(PetscSectionGetOffset(coordSection, v, &off));
615: PetscCall(PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Internal(v, depth, depthShift), &noff));
616: for (d = 0; d < dof; ++d) newCoords[noff + d] = coords[off + d];
617: }
618: PetscCall(VecRestoreArray(coordinates, &coords));
619: PetscCall(VecRestoreArray(newCoordinates, &newCoords));
620: PetscCall(VecDestroy(&newCoordinates));
621: PetscCall(PetscSectionDestroy(&newCoordSection));
622: PetscFunctionReturn(PETSC_SUCCESS);
623: }
625: static PetscErrorCode DMPlexShiftSF_Single(DM dm, PetscInt depthShift[], PetscSF sf, PetscSF sfNew)
626: {
627: const PetscSFNode *remotePoints;
628: PetscSFNode *gremotePoints;
629: const PetscInt *localPoints;
630: PetscInt *glocalPoints, *newLocation, *newRemoteLocation;
631: PetscInt numRoots, numLeaves, l, pStart, pEnd, depth = 0, totShift = 0;
633: PetscFunctionBegin;
634: PetscCall(DMPlexGetDepth(dm, &depth));
635: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
636: PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
637: totShift = DMPlexShiftPoint_Internal(pEnd, depth, depthShift) - pEnd;
638: if (numRoots >= 0) {
639: PetscCall(PetscMalloc2(numRoots, &newLocation, pEnd - pStart, &newRemoteLocation));
640: for (l = 0; l < numRoots; ++l) newLocation[l] = DMPlexShiftPoint_Internal(l, depth, depthShift);
641: PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newLocation, newRemoteLocation, MPI_REPLACE));
642: PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newLocation, newRemoteLocation, MPI_REPLACE));
643: PetscCall(PetscMalloc1(numLeaves, &glocalPoints));
644: PetscCall(PetscMalloc1(numLeaves, &gremotePoints));
645: for (l = 0; l < numLeaves; ++l) {
646: glocalPoints[l] = DMPlexShiftPoint_Internal(localPoints[l], depth, depthShift);
647: gremotePoints[l].rank = remotePoints[l].rank;
648: gremotePoints[l].index = newRemoteLocation[localPoints[l]];
649: }
650: PetscCall(PetscFree2(newLocation, newRemoteLocation));
651: PetscCall(PetscSFSetGraph(sfNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER));
652: }
653: PetscFunctionReturn(PETSC_SUCCESS);
654: }
656: static PetscErrorCode DMPlexShiftSF_Internal(DM dm, PetscInt depthShift[], DM dmNew)
657: {
658: PetscSF sfPoint, sfPointNew;
659: PetscBool useNatural;
661: PetscFunctionBegin;
662: /* Step 9: Convert pointSF */
663: PetscCall(DMGetPointSF(dm, &sfPoint));
664: PetscCall(DMGetPointSF(dmNew, &sfPointNew));
665: PetscCall(DMPlexShiftSF_Single(dm, depthShift, sfPoint, sfPointNew));
666: /* Step 9b: Convert naturalSF */
667: PetscCall(DMGetUseNatural(dm, &useNatural));
668: if (useNatural) {
669: PetscSF sfNat, sfNatNew;
671: PetscCall(DMSetUseNatural(dmNew, useNatural));
672: PetscCall(DMGetNaturalSF(dm, &sfNat));
673: PetscCall(DMGetNaturalSF(dmNew, &sfNatNew));
674: PetscCall(DMPlexShiftSF_Single(dm, depthShift, sfNat, sfNatNew));
675: }
676: PetscFunctionReturn(PETSC_SUCCESS);
677: }
679: static PetscErrorCode DMPlexShiftLabels_Internal(DM dm, PetscInt depthShift[], DM dmNew)
680: {
681: PetscInt depth = 0, numLabels, l;
683: PetscFunctionBegin;
684: PetscCall(DMPlexGetDepth(dm, &depth));
685: /* Step 10: Convert labels */
686: PetscCall(DMGetNumLabels(dm, &numLabels));
687: for (l = 0; l < numLabels; ++l) {
688: DMLabel label, newlabel;
689: const char *lname;
690: PetscBool isDepth, isDim;
691: IS valueIS;
692: const PetscInt *values;
693: PetscInt numValues, val;
695: PetscCall(DMGetLabelName(dm, l, &lname));
696: PetscCall(PetscStrcmp(lname, "depth", &isDepth));
697: if (isDepth) continue;
698: PetscCall(PetscStrcmp(lname, "dim", &isDim));
699: if (isDim) continue;
700: PetscCall(DMCreateLabel(dmNew, lname));
701: PetscCall(DMGetLabel(dm, lname, &label));
702: PetscCall(DMGetLabel(dmNew, lname, &newlabel));
703: PetscCall(DMLabelGetDefaultValue(label, &val));
704: PetscCall(DMLabelSetDefaultValue(newlabel, val));
705: PetscCall(DMLabelGetValueIS(label, &valueIS));
706: PetscCall(ISGetLocalSize(valueIS, &numValues));
707: PetscCall(ISGetIndices(valueIS, &values));
708: for (val = 0; val < numValues; ++val) {
709: IS pointIS;
710: const PetscInt *points;
711: PetscInt numPoints, p;
713: PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
714: PetscCall(ISGetLocalSize(pointIS, &numPoints));
715: PetscCall(ISGetIndices(pointIS, &points));
716: for (p = 0; p < numPoints; ++p) {
717: const PetscInt newpoint = DMPlexShiftPoint_Internal(points[p], depth, depthShift);
719: PetscCall(DMLabelSetValue(newlabel, newpoint, values[val]));
720: }
721: PetscCall(ISRestoreIndices(pointIS, &points));
722: PetscCall(ISDestroy(&pointIS));
723: }
724: PetscCall(ISRestoreIndices(valueIS, &values));
725: PetscCall(ISDestroy(&valueIS));
726: }
727: PetscFunctionReturn(PETSC_SUCCESS);
728: }
730: static PetscErrorCode DMPlexCreateVTKLabel_Internal(DM dm, PetscBool createGhostLabel, DM dmNew)
731: {
732: PetscSF sfPoint;
733: DMLabel vtkLabel, ghostLabel = NULL;
734: const PetscSFNode *leafRemote;
735: const PetscInt *leafLocal;
736: PetscInt cellHeight, cStart, cEnd, c, fStart, fEnd, f, numLeaves, l;
737: PetscMPIInt rank;
739: PetscFunctionBegin;
740: /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
741: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
742: PetscCall(DMGetPointSF(dm, &sfPoint));
743: PetscCall(DMPlexGetVTKCellHeight(dmNew, &cellHeight));
744: PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
745: PetscCall(PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote));
746: PetscCall(DMCreateLabel(dmNew, "vtk"));
747: PetscCall(DMGetLabel(dmNew, "vtk", &vtkLabel));
748: if (createGhostLabel) {
749: PetscCall(DMCreateLabel(dmNew, "ghost"));
750: PetscCall(DMGetLabel(dmNew, "ghost", &ghostLabel));
751: }
752: for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
753: for (; c < leafLocal[l] && c < cEnd; ++c) PetscCall(DMLabelSetValue(vtkLabel, c, 1));
754: if (leafLocal[l] >= cEnd) break;
755: if (leafRemote[l].rank == rank) {
756: PetscCall(DMLabelSetValue(vtkLabel, c, 1));
757: } else if (ghostLabel) PetscCall(DMLabelSetValue(ghostLabel, c, 2));
758: }
759: for (; c < cEnd; ++c) PetscCall(DMLabelSetValue(vtkLabel, c, 1));
760: if (ghostLabel) {
761: PetscCall(DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd));
762: for (f = fStart; f < fEnd; ++f) {
763: PetscInt numCells;
765: PetscCall(DMPlexGetSupportSize(dmNew, f, &numCells));
766: if (numCells < 2) {
767: PetscCall(DMLabelSetValue(ghostLabel, f, 1));
768: } else {
769: const PetscInt *cells = NULL;
770: PetscInt vA, vB;
772: PetscCall(DMPlexGetSupport(dmNew, f, &cells));
773: PetscCall(DMLabelGetValue(vtkLabel, cells[0], &vA));
774: PetscCall(DMLabelGetValue(vtkLabel, cells[1], &vB));
775: if (vA != 1 && vB != 1) PetscCall(DMLabelSetValue(ghostLabel, f, 1));
776: }
777: }
778: }
779: PetscFunctionReturn(PETSC_SUCCESS);
780: }
782: static PetscErrorCode DMPlexShiftTree_Internal(DM dm, PetscInt depthShift[], DM dmNew)
783: {
784: DM refTree;
785: PetscSection pSec;
786: PetscInt *parents, *childIDs;
788: PetscFunctionBegin;
789: PetscCall(DMPlexGetReferenceTree(dm, &refTree));
790: PetscCall(DMPlexSetReferenceTree(dmNew, refTree));
791: PetscCall(DMPlexGetTree(dm, &pSec, &parents, &childIDs, NULL, NULL));
792: if (pSec) {
793: PetscInt p, pStart, pEnd, *parentsShifted, pStartShifted, pEndShifted, depth;
794: PetscInt *childIDsShifted;
795: PetscSection pSecShifted;
797: PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
798: PetscCall(DMPlexGetDepth(dm, &depth));
799: pStartShifted = DMPlexShiftPoint_Internal(pStart, depth, depthShift);
800: pEndShifted = DMPlexShiftPoint_Internal(pEnd, depth, depthShift);
801: PetscCall(PetscMalloc2(pEndShifted - pStartShifted, &parentsShifted, pEndShifted - pStartShifted, &childIDsShifted));
802: PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmNew), &pSecShifted));
803: PetscCall(PetscSectionSetChart(pSecShifted, pStartShifted, pEndShifted));
804: for (p = pStartShifted; p < pEndShifted; p++) {
805: /* start off assuming no children */
806: PetscCall(PetscSectionSetDof(pSecShifted, p, 0));
807: }
808: for (p = pStart; p < pEnd; p++) {
809: PetscInt dof;
810: PetscInt pNew = DMPlexShiftPoint_Internal(p, depth, depthShift);
812: PetscCall(PetscSectionGetDof(pSec, p, &dof));
813: PetscCall(PetscSectionSetDof(pSecShifted, pNew, dof));
814: }
815: PetscCall(PetscSectionSetUp(pSecShifted));
816: for (p = pStart; p < pEnd; p++) {
817: PetscInt dof;
818: PetscInt pNew = DMPlexShiftPoint_Internal(p, depth, depthShift);
820: PetscCall(PetscSectionGetDof(pSec, p, &dof));
821: if (dof) {
822: PetscInt off, offNew;
824: PetscCall(PetscSectionGetOffset(pSec, p, &off));
825: PetscCall(PetscSectionGetOffset(pSecShifted, pNew, &offNew));
826: parentsShifted[offNew] = DMPlexShiftPoint_Internal(parents[off], depth, depthShift);
827: childIDsShifted[offNew] = childIDs[off];
828: }
829: }
830: PetscCall(DMPlexSetTree(dmNew, pSecShifted, parentsShifted, childIDsShifted));
831: PetscCall(PetscFree2(parentsShifted, childIDsShifted));
832: PetscCall(PetscSectionDestroy(&pSecShifted));
833: }
834: PetscFunctionReturn(PETSC_SUCCESS);
835: }
837: static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, DMLabel label, PetscInt *numGhostCells, DM gdm)
838: {
839: PetscSF sf;
840: IS valueIS;
841: const PetscInt *values, *leaves;
842: PetscInt *depthShift;
843: PetscInt d, depth = 0, nleaves, loc, Ng, numFS, fs, fStart, fEnd, ghostCell, cEnd, c;
844: const PetscReal *maxCell, *Lstart, *L;
846: PetscFunctionBegin;
847: PetscCall(DMGetPointSF(dm, &sf));
848: PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
849: nleaves = PetscMax(0, nleaves);
850: PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
851: /* Count ghost cells */
852: PetscCall(DMLabelGetValueIS(label, &valueIS));
853: PetscCall(ISGetLocalSize(valueIS, &numFS));
854: PetscCall(ISGetIndices(valueIS, &values));
855: Ng = 0;
856: for (fs = 0; fs < numFS; ++fs) {
857: IS faceIS;
858: const PetscInt *faces;
859: PetscInt numFaces, f, numBdFaces = 0;
861: PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS));
862: PetscCall(ISGetLocalSize(faceIS, &numFaces));
863: PetscCall(ISGetIndices(faceIS, &faces));
864: for (f = 0; f < numFaces; ++f) {
865: PetscInt numChildren;
867: PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc));
868: PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL));
869: /* non-local and ancestors points don't get to register ghosts */
870: if (loc >= 0 || numChildren) continue;
871: if ((faces[f] >= fStart) && (faces[f] < fEnd)) ++numBdFaces;
872: }
873: Ng += numBdFaces;
874: PetscCall(ISRestoreIndices(faceIS, &faces));
875: PetscCall(ISDestroy(&faceIS));
876: }
877: PetscCall(DMPlexGetDepth(dm, &depth));
878: PetscCall(PetscMalloc1(2 * (depth + 1), &depthShift));
879: for (d = 0; d <= depth; d++) {
880: PetscInt dEnd;
882: PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &dEnd));
883: depthShift[2 * d] = dEnd;
884: depthShift[2 * d + 1] = 0;
885: }
886: if (depth >= 0) depthShift[2 * depth + 1] = Ng;
887: PetscCall(DMPlexShiftPointSetUp_Internal(depth, depthShift));
888: PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, gdm));
889: /* Step 3: Set cone/support sizes for new points */
890: PetscCall(DMPlexGetHeightStratum(dm, 0, NULL, &cEnd));
891: for (c = cEnd; c < cEnd + Ng; ++c) PetscCall(DMPlexSetConeSize(gdm, c, 1));
892: for (fs = 0; fs < numFS; ++fs) {
893: IS faceIS;
894: const PetscInt *faces;
895: PetscInt numFaces, f;
897: PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS));
898: PetscCall(ISGetLocalSize(faceIS, &numFaces));
899: PetscCall(ISGetIndices(faceIS, &faces));
900: for (f = 0; f < numFaces; ++f) {
901: PetscInt size, numChildren;
903: PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc));
904: PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL));
905: if (loc >= 0 || numChildren) continue;
906: if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
907: PetscCall(DMPlexGetSupportSize(dm, faces[f], &size));
908: PetscCheck(size == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM has boundary face %" PetscInt_FMT " with %" PetscInt_FMT " support cells", faces[f], size);
909: PetscCall(DMPlexSetSupportSize(gdm, faces[f] + Ng, 2));
910: }
911: PetscCall(ISRestoreIndices(faceIS, &faces));
912: PetscCall(ISDestroy(&faceIS));
913: }
914: /* Step 4: Setup ghosted DM */
915: PetscCall(DMSetUp(gdm));
916: PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, gdm));
917: /* Step 6: Set cones and supports for new points */
918: ghostCell = cEnd;
919: for (fs = 0; fs < numFS; ++fs) {
920: IS faceIS;
921: const PetscInt *faces;
922: PetscInt numFaces, f;
924: PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS));
925: PetscCall(ISGetLocalSize(faceIS, &numFaces));
926: PetscCall(ISGetIndices(faceIS, &faces));
927: for (f = 0; f < numFaces; ++f) {
928: PetscInt newFace = faces[f] + Ng, numChildren;
930: PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc));
931: PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL));
932: if (loc >= 0 || numChildren) continue;
933: if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
934: PetscCall(DMPlexSetCone(gdm, ghostCell, &newFace));
935: PetscCall(DMPlexInsertSupport(gdm, newFace, 1, ghostCell));
936: ++ghostCell;
937: }
938: PetscCall(ISRestoreIndices(faceIS, &faces));
939: PetscCall(ISDestroy(&faceIS));
940: }
941: PetscCall(ISRestoreIndices(valueIS, &values));
942: PetscCall(ISDestroy(&valueIS));
943: PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, gdm));
944: PetscCall(DMPlexShiftSF_Internal(dm, depthShift, gdm));
945: PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, gdm));
946: PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_TRUE, gdm));
947: PetscCall(DMPlexShiftTree_Internal(dm, depthShift, gdm));
948: PetscCall(PetscFree(depthShift));
949: for (c = cEnd; c < cEnd + Ng; ++c) PetscCall(DMPlexSetCellType(gdm, c, DM_POLYTOPE_FV_GHOST));
950: /* Step 7: Periodicity */
951: PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
952: PetscCall(DMSetPeriodicity(gdm, maxCell, Lstart, L));
953: if (numGhostCells) *numGhostCells = Ng;
954: PetscFunctionReturn(PETSC_SUCCESS);
955: }
957: /*@C
958: DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
960: Collective on dm
962: Input Parameters:
963: + dm - The original DM
964: - labelName - The label specifying the boundary faces, or "Face Sets" if this is NULL
966: Output Parameters:
967: + numGhostCells - The number of ghost cells added to the DM
968: - dmGhosted - The new DM
970: Note: If no label exists of that name, one will be created marking all boundary faces
972: Level: developer
974: .seealso: `DMCreate()`
975: @*/
976: PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
977: {
978: DM gdm;
979: DMLabel label;
980: const char *name = labelName ? labelName : "Face Sets";
981: PetscInt dim, Ng = 0;
982: PetscBool useCone, useClosure;
984: PetscFunctionBegin;
988: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &gdm));
989: PetscCall(DMSetType(gdm, DMPLEX));
990: PetscCall(DMGetDimension(dm, &dim));
991: PetscCall(DMSetDimension(gdm, dim));
992: PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
993: PetscCall(DMSetBasicAdjacency(gdm, useCone, useClosure));
994: PetscCall(DMGetLabel(dm, name, &label));
995: if (!label) {
996: /* Get label for boundary faces */
997: PetscCall(DMCreateLabel(dm, name));
998: PetscCall(DMGetLabel(dm, name, &label));
999: PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
1000: }
1001: PetscCall(DMPlexConstructGhostCells_Internal(dm, label, &Ng, gdm));
1002: PetscCall(DMCopyDisc(dm, gdm));
1003: PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, gdm));
1004: gdm->setfromoptionscalled = dm->setfromoptionscalled;
1005: if (numGhostCells) *numGhostCells = Ng;
1006: *dmGhosted = gdm;
1007: PetscFunctionReturn(PETSC_SUCCESS);
1008: }
1010: static PetscErrorCode DivideCells_Private(DM dm, DMLabel label, DMPlexPointQueue queue)
1011: {
1012: PetscInt dim, d, shift = 100, *pStart, *pEnd;
1014: PetscFunctionBegin;
1015: PetscCall(DMGetDimension(dm, &dim));
1016: PetscCall(PetscMalloc2(dim, &pStart, dim, &pEnd));
1017: for (d = 0; d < dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]));
1018: while (!DMPlexPointQueueEmpty(queue)) {
1019: PetscInt cell = -1;
1020: PetscInt *closure = NULL;
1021: PetscInt closureSize, cl, cval;
1023: PetscCall(DMPlexPointQueueDequeue(queue, &cell));
1024: PetscCall(DMLabelGetValue(label, cell, &cval));
1025: PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1026: /* Mark points in the cell closure that touch the fault */
1027: for (d = 0; d < dim; ++d) {
1028: for (cl = 0; cl < closureSize * 2; cl += 2) {
1029: const PetscInt clp = closure[cl];
1030: PetscInt clval;
1032: if ((clp < pStart[d]) || (clp >= pEnd[d])) continue;
1033: PetscCall(DMLabelGetValue(label, clp, &clval));
1034: if (clval == -1) {
1035: const PetscInt *cone;
1036: PetscInt coneSize, c;
1038: /* If a cone point touches the fault, then this point touches the fault */
1039: PetscCall(DMPlexGetCone(dm, clp, &cone));
1040: PetscCall(DMPlexGetConeSize(dm, clp, &coneSize));
1041: for (c = 0; c < coneSize; ++c) {
1042: PetscInt cpval;
1044: PetscCall(DMLabelGetValue(label, cone[c], &cpval));
1045: if (cpval != -1) {
1046: PetscInt dep;
1048: PetscCall(DMPlexGetPointDepth(dm, clp, &dep));
1049: clval = cval < 0 ? -(shift + dep) : shift + dep;
1050: PetscCall(DMLabelSetValue(label, clp, clval));
1051: break;
1052: }
1053: }
1054: }
1055: /* Mark neighbor cells through marked faces (these cells must also touch the fault) */
1056: if (d == dim - 1 && clval != -1) {
1057: const PetscInt *support;
1058: PetscInt supportSize, s, nval;
1060: PetscCall(DMPlexGetSupport(dm, clp, &support));
1061: PetscCall(DMPlexGetSupportSize(dm, clp, &supportSize));
1062: for (s = 0; s < supportSize; ++s) {
1063: PetscCall(DMLabelGetValue(label, support[s], &nval));
1064: if (nval == -1) {
1065: PetscCall(DMLabelSetValue(label, support[s], clval < 0 ? clval - 1 : clval + 1));
1066: PetscCall(DMPlexPointQueueEnqueue(queue, support[s]));
1067: }
1068: }
1069: }
1070: }
1071: }
1072: PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1073: }
1074: PetscCall(PetscFree2(pStart, pEnd));
1075: PetscFunctionReturn(PETSC_SUCCESS);
1076: }
1078: typedef struct {
1079: DM dm;
1080: DMPlexPointQueue queue;
1081: } PointDivision;
1083: static PetscErrorCode divideCell(DMLabel label, PetscInt p, PetscInt val, void *ctx)
1084: {
1085: PointDivision *div = (PointDivision *)ctx;
1086: PetscInt cval = val < 0 ? val - 1 : val + 1;
1087: const PetscInt *support;
1088: PetscInt supportSize, s;
1090: PetscFunctionBegin;
1091: PetscCall(DMPlexGetSupport(div->dm, p, &support));
1092: PetscCall(DMPlexGetSupportSize(div->dm, p, &supportSize));
1093: for (s = 0; s < supportSize; ++s) {
1094: PetscCall(DMLabelSetValue(label, support[s], cval));
1095: PetscCall(DMPlexPointQueueEnqueue(div->queue, support[s]));
1096: }
1097: PetscFunctionReturn(PETSC_SUCCESS);
1098: }
1100: /* Mark cells by label propagation */
1101: static PetscErrorCode DMPlexLabelFaultHalo(DM dm, DMLabel faultLabel)
1102: {
1103: DMPlexPointQueue queue = NULL;
1104: PointDivision div;
1105: PetscSF pointSF;
1106: IS pointIS;
1107: const PetscInt *points;
1108: PetscBool empty;
1109: PetscInt dim, shift = 100, n, i;
1111: PetscFunctionBegin;
1112: PetscCall(DMGetDimension(dm, &dim));
1113: PetscCall(DMPlexPointQueueCreate(1024, &queue));
1114: div.dm = dm;
1115: div.queue = queue;
1116: /* Enqueue cells on fault */
1117: PetscCall(DMLabelGetStratumIS(faultLabel, shift + dim, &pointIS));
1118: if (pointIS) {
1119: PetscCall(ISGetLocalSize(pointIS, &n));
1120: PetscCall(ISGetIndices(pointIS, &points));
1121: for (i = 0; i < n; ++i) PetscCall(DMPlexPointQueueEnqueue(queue, points[i]));
1122: PetscCall(ISRestoreIndices(pointIS, &points));
1123: PetscCall(ISDestroy(&pointIS));
1124: }
1125: PetscCall(DMLabelGetStratumIS(faultLabel, -(shift + dim), &pointIS));
1126: if (pointIS) {
1127: PetscCall(ISGetLocalSize(pointIS, &n));
1128: PetscCall(ISGetIndices(pointIS, &points));
1129: for (i = 0; i < n; ++i) PetscCall(DMPlexPointQueueEnqueue(queue, points[i]));
1130: PetscCall(ISRestoreIndices(pointIS, &points));
1131: PetscCall(ISDestroy(&pointIS));
1132: }
1134: PetscCall(DMGetPointSF(dm, &pointSF));
1135: PetscCall(DMLabelPropagateBegin(faultLabel, pointSF));
1136: /* While edge queue is not empty: */
1137: PetscCall(DMPlexPointQueueEmptyCollective((PetscObject)dm, queue, &empty));
1138: while (!empty) {
1139: PetscCall(DivideCells_Private(dm, faultLabel, queue));
1140: PetscCall(DMLabelPropagatePush(faultLabel, pointSF, divideCell, &div));
1141: PetscCall(DMPlexPointQueueEmptyCollective((PetscObject)dm, queue, &empty));
1142: }
1143: PetscCall(DMLabelPropagateEnd(faultLabel, pointSF));
1144: PetscCall(DMPlexPointQueueDestroy(&queue));
1145: PetscFunctionReturn(PETSC_SUCCESS);
1146: }
1148: /*
1149: We are adding three kinds of points here:
1150: Replicated: Copies of points which exist in the mesh, such as vertices identified across a fault
1151: Non-replicated: Points which exist on the fault, but are not replicated
1152: Ghost: These are shared fault faces which are not owned by this process. These do not produce hybrid cells and do not replicate
1153: Hybrid: Entirely new points, such as cohesive cells
1155: When creating subsequent cohesive cells, we shift the old hybrid cells to the end of the numbering at
1156: each depth so that the new split/hybrid points can be inserted as a block.
1157: */
1158: static PetscErrorCode DMPlexConstructCohesiveCells_Internal(DM dm, DMLabel label, DMLabel splitLabel, DM sdm)
1159: {
1160: MPI_Comm comm;
1161: IS valueIS;
1162: PetscInt numSP = 0; /* The number of depths for which we have replicated points */
1163: const PetscInt *values; /* List of depths for which we have replicated points */
1164: IS *splitIS;
1165: IS *unsplitIS;
1166: IS ghostIS;
1167: PetscInt *numSplitPoints; /* The number of replicated points at each depth */
1168: PetscInt *numUnsplitPoints; /* The number of non-replicated points at each depth which still give rise to hybrid points */
1169: PetscInt *numHybridPoints; /* The number of new hybrid points at each depth */
1170: PetscInt *numHybridPointsOld; /* The number of existing hybrid points at each depth */
1171: PetscInt numGhostPoints; /* The number of unowned, shared fault faces */
1172: const PetscInt **splitPoints; /* Replicated points for each depth */
1173: const PetscInt **unsplitPoints; /* Non-replicated points for each depth */
1174: const PetscInt *ghostPoints; /* Ghost fault faces */
1175: PetscSection coordSection;
1176: Vec coordinates;
1177: PetscScalar *coords;
1178: PetscInt *depthMax; /* The first hybrid point at each depth in the original mesh */
1179: PetscInt *depthEnd; /* The point limit at each depth in the original mesh */
1180: PetscInt *depthShift; /* Number of replicated+hybrid points at each depth */
1181: PetscInt *pMaxNew; /* The first replicated point at each depth in the new mesh, hybrids come after this */
1182: PetscInt *coneNew, *coneONew, *supportNew;
1183: PetscInt shift = 100, shift2 = 200, depth = 0, dep, dim, d, sp, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, numLabels, vStart, vEnd, pEnd, p, v;
1185: PetscFunctionBegin;
1186: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1187: PetscCall(DMGetDimension(dm, &dim));
1188: PetscCall(DMPlexGetDepth(dm, &depth));
1189: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1190: /* We do not want this label automatically computed, instead we compute it here */
1191: PetscCall(DMCreateLabel(sdm, "celltype"));
1192: /* Count split points and add cohesive cells */
1193: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
1194: PetscCall(PetscMalloc5(depth + 1, &depthMax, depth + 1, &depthEnd, 2 * (depth + 1), &depthShift, depth + 1, &pMaxNew, depth + 1, &numHybridPointsOld));
1195: PetscCall(PetscMalloc7(depth + 1, &splitIS, depth + 1, &unsplitIS, depth + 1, &numSplitPoints, depth + 1, &numUnsplitPoints, depth + 1, &numHybridPoints, depth + 1, &splitPoints, depth + 1, &unsplitPoints));
1196: for (d = 0; d <= depth; ++d) {
1197: PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]));
1198: PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, d, &depthMax[d], NULL));
1199: depthEnd[d] = pMaxNew[d];
1200: depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
1201: numSplitPoints[d] = 0;
1202: numUnsplitPoints[d] = 0;
1203: numHybridPoints[d] = 0;
1204: numHybridPointsOld[d] = depthMax[d] < 0 ? 0 : depthEnd[d] - depthMax[d];
1205: splitPoints[d] = NULL;
1206: unsplitPoints[d] = NULL;
1207: splitIS[d] = NULL;
1208: unsplitIS[d] = NULL;
1209: /* we are shifting the existing hybrid points with the stratum behind them, so
1210: * the split comes at the end of the normal points, i.e., at depthMax[d] */
1211: depthShift[2 * d] = depthMax[d];
1212: depthShift[2 * d + 1] = 0;
1213: }
1214: numGhostPoints = 0;
1215: ghostPoints = NULL;
1216: if (label) {
1217: PetscCall(DMLabelGetValueIS(label, &valueIS));
1218: PetscCall(ISGetLocalSize(valueIS, &numSP));
1219: PetscCall(ISGetIndices(valueIS, &values));
1220: }
1221: for (sp = 0; sp < numSP; ++sp) {
1222: const PetscInt dep = values[sp];
1224: if ((dep < 0) || (dep > depth)) continue;
1225: PetscCall(DMLabelGetStratumIS(label, dep, &splitIS[dep]));
1226: if (splitIS[dep]) {
1227: PetscCall(ISGetLocalSize(splitIS[dep], &numSplitPoints[dep]));
1228: PetscCall(ISGetIndices(splitIS[dep], &splitPoints[dep]));
1229: }
1230: PetscCall(DMLabelGetStratumIS(label, shift2 + dep, &unsplitIS[dep]));
1231: if (unsplitIS[dep]) {
1232: PetscCall(ISGetLocalSize(unsplitIS[dep], &numUnsplitPoints[dep]));
1233: PetscCall(ISGetIndices(unsplitIS[dep], &unsplitPoints[dep]));
1234: }
1235: }
1236: PetscCall(DMLabelGetStratumIS(label, shift2 + dim - 1, &ghostIS));
1237: if (ghostIS) {
1238: PetscCall(ISGetLocalSize(ghostIS, &numGhostPoints));
1239: PetscCall(ISGetIndices(ghostIS, &ghostPoints));
1240: }
1241: /* Calculate number of hybrid points */
1242: for (d = 1; d <= depth; ++d) numHybridPoints[d] = numSplitPoints[d - 1] + numUnsplitPoints[d - 1]; /* There is a hybrid cell/face/edge for every split face/edge/vertex */
1243: for (d = 0; d <= depth; ++d) depthShift[2 * d + 1] = numSplitPoints[d] + numHybridPoints[d];
1244: PetscCall(DMPlexShiftPointSetUp_Internal(depth, depthShift));
1245: /* the end of the points in this stratum that come before the new points:
1246: * shifting pMaxNew[d] gets the new start of the next stratum, then count back the old hybrid points and the newly
1247: * added points */
1248: for (d = 0; d <= depth; ++d) pMaxNew[d] = DMPlexShiftPoint_Internal(pMaxNew[d], depth, depthShift) - (numHybridPointsOld[d] + numSplitPoints[d] + numHybridPoints[d]);
1249: PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, sdm));
1250: /* Step 3: Set cone/support sizes for new points */
1251: for (dep = 0; dep <= depth; ++dep) {
1252: for (p = 0; p < numSplitPoints[dep]; ++p) {
1253: const PetscInt oldp = splitPoints[dep][p];
1254: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1255: const PetscInt splitp = p + pMaxNew[dep];
1256: const PetscInt *support;
1257: DMPolytopeType ct;
1258: PetscInt coneSize, supportSize, qf, qn, qp, e;
1260: PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1261: PetscCall(DMPlexSetConeSize(sdm, splitp, coneSize));
1262: PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1263: PetscCall(DMPlexSetSupportSize(sdm, splitp, supportSize));
1264: PetscCall(DMPlexGetCellType(dm, oldp, &ct));
1265: PetscCall(DMPlexSetCellType(sdm, splitp, ct));
1266: if (dep == depth - 1) {
1267: const PetscInt hybcell = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1269: /* Add cohesive cells, they are prisms */
1270: PetscCall(DMPlexSetConeSize(sdm, hybcell, 2 + coneSize));
1271: switch (coneSize) {
1272: case 2:
1273: PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_SEG_PRISM_TENSOR));
1274: break;
1275: case 3:
1276: PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_TRI_PRISM_TENSOR));
1277: break;
1278: case 4:
1279: PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_QUAD_PRISM_TENSOR));
1280: break;
1281: }
1282: /* Shared fault faces with only one support cell now have two with the cohesive cell */
1283: /* TODO Check thaat oldp has rootdegree == 1 */
1284: if (supportSize == 1) {
1285: const PetscInt *support;
1286: PetscInt val;
1288: PetscCall(DMPlexGetSupport(dm, oldp, &support));
1289: PetscCall(DMLabelGetValue(label, support[0], &val));
1290: if (val < 0) PetscCall(DMPlexSetSupportSize(sdm, splitp, 2));
1291: else PetscCall(DMPlexSetSupportSize(sdm, newp, 2));
1292: }
1293: } else if (dep == 0) {
1294: const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1296: PetscCall(DMPlexGetSupport(dm, oldp, &support));
1297: for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
1298: PetscInt val;
1300: PetscCall(DMLabelGetValue(label, support[e], &val));
1301: if (val == 1) ++qf;
1302: if ((val == 1) || (val == (shift + 1))) ++qn;
1303: if ((val == 1) || (val == -(shift + 1))) ++qp;
1304: }
1305: /* Split old vertex: Edges into original vertex and new cohesive edge */
1306: PetscCall(DMPlexSetSupportSize(sdm, newp, qn + 1));
1307: /* Split new vertex: Edges into split vertex and new cohesive edge */
1308: PetscCall(DMPlexSetSupportSize(sdm, splitp, qp + 1));
1309: /* Add hybrid edge */
1310: PetscCall(DMPlexSetConeSize(sdm, hybedge, 2));
1311: PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf));
1312: PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR));
1313: } else if (dep == dim - 2) {
1314: const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1316: PetscCall(DMPlexGetSupport(dm, oldp, &support));
1317: for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
1318: PetscInt val;
1320: PetscCall(DMLabelGetValue(label, support[e], &val));
1321: if (val == dim - 1) ++qf;
1322: if ((val == dim - 1) || (val == (shift + dim - 1))) ++qn;
1323: if ((val == dim - 1) || (val == -(shift + dim - 1))) ++qp;
1324: }
1325: /* Split old edge: Faces into original edge and cohesive face (positive side?) */
1326: PetscCall(DMPlexSetSupportSize(sdm, newp, qn + 1));
1327: /* Split new edge: Faces into split edge and cohesive face (negative side?) */
1328: PetscCall(DMPlexSetSupportSize(sdm, splitp, qp + 1));
1329: /* Add hybrid face */
1330: PetscCall(DMPlexSetConeSize(sdm, hybface, 4));
1331: PetscCall(DMPlexSetSupportSize(sdm, hybface, qf));
1332: PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR));
1333: }
1334: }
1335: }
1336: for (dep = 0; dep <= depth; ++dep) {
1337: for (p = 0; p < numUnsplitPoints[dep]; ++p) {
1338: const PetscInt oldp = unsplitPoints[dep][p];
1339: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1340: const PetscInt *support;
1341: PetscInt coneSize, supportSize, qf, e, s;
1343: PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1344: PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1345: PetscCall(DMPlexGetSupport(dm, oldp, &support));
1346: if (dep == 0) {
1347: const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];
1349: /* Unsplit vertex: Edges into original vertex, split edges, and new cohesive edge twice */
1350: for (s = 0, qf = 0; s < supportSize; ++s, ++qf) {
1351: PetscCall(PetscFindInt(support[s], numSplitPoints[dep + 1], splitPoints[dep + 1], &e));
1352: if (e >= 0) ++qf;
1353: }
1354: PetscCall(DMPlexSetSupportSize(sdm, newp, qf + 2));
1355: /* Add hybrid edge */
1356: PetscCall(DMPlexSetConeSize(sdm, hybedge, 2));
1357: for (e = 0, qf = 0; e < supportSize; ++e) {
1358: PetscInt val;
1360: PetscCall(DMLabelGetValue(label, support[e], &val));
1361: /* Split and unsplit edges produce hybrid faces */
1362: if (val == 1) ++qf;
1363: if (val == (shift2 + 1)) ++qf;
1364: }
1365: PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf));
1366: PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR));
1367: } else if (dep == dim - 2) {
1368: const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];
1369: PetscInt val;
1371: for (e = 0, qf = 0; e < supportSize; ++e) {
1372: PetscCall(DMLabelGetValue(label, support[e], &val));
1373: if (val == dim - 1) qf += 2;
1374: else ++qf;
1375: }
1376: /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */
1377: PetscCall(DMPlexSetSupportSize(sdm, newp, qf + 2));
1378: /* Add hybrid face */
1379: for (e = 0, qf = 0; e < supportSize; ++e) {
1380: PetscCall(DMLabelGetValue(label, support[e], &val));
1381: if (val == dim - 1) ++qf;
1382: }
1383: PetscCall(DMPlexSetConeSize(sdm, hybface, 4));
1384: PetscCall(DMPlexSetSupportSize(sdm, hybface, qf));
1385: PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR));
1386: }
1387: }
1388: }
1389: /* Step 4: Setup split DM */
1390: PetscCall(DMSetUp(sdm));
1391: PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, sdm));
1392: PetscCall(DMPlexGetMaxSizes(sdm, &maxConeSizeNew, &maxSupportSizeNew));
1393: PetscCall(PetscMalloc3(PetscMax(maxConeSize, maxConeSizeNew) * 3, &coneNew, PetscMax(maxConeSize, maxConeSizeNew) * 3, &coneONew, PetscMax(maxSupportSize, maxSupportSizeNew), &supportNew));
1394: /* Step 6: Set cones and supports for new points */
1395: for (dep = 0; dep <= depth; ++dep) {
1396: for (p = 0; p < numSplitPoints[dep]; ++p) {
1397: const PetscInt oldp = splitPoints[dep][p];
1398: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1399: const PetscInt splitp = p + pMaxNew[dep];
1400: const PetscInt *cone, *support, *ornt;
1401: DMPolytopeType ct;
1402: PetscInt coneSize, supportSize, q, qf, qn, qp, v, e, s;
1404: PetscCall(DMPlexGetCellType(dm, oldp, &ct));
1405: PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1406: PetscCall(DMPlexGetCone(dm, oldp, &cone));
1407: PetscCall(DMPlexGetConeOrientation(dm, oldp, &ornt));
1408: PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1409: PetscCall(DMPlexGetSupport(dm, oldp, &support));
1410: if (dep == depth - 1) {
1411: PetscBool hasUnsplit = PETSC_FALSE;
1412: const PetscInt hybcell = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1413: const PetscInt *supportF;
1415: coneONew[0] = coneONew[1] = -1000;
1416: /* Split face: copy in old face to new face to start */
1417: PetscCall(DMPlexGetSupport(sdm, newp, &supportF));
1418: PetscCall(DMPlexSetSupport(sdm, splitp, supportF));
1419: /* Split old face: old vertices/edges in cone so no change */
1420: /* Split new face: new vertices/edges in cone */
1421: for (q = 0; q < coneSize; ++q) {
1422: PetscCall(PetscFindInt(cone[q], numSplitPoints[dep - 1], splitPoints[dep - 1], &v));
1423: if (v < 0) {
1424: PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1425: PetscCheck(v >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[q], dep - 1);
1426: coneNew[2 + q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/;
1427: hasUnsplit = PETSC_TRUE;
1428: } else {
1429: coneNew[2 + q] = v + pMaxNew[dep - 1];
1430: if (dep > 1) {
1431: const PetscInt *econe;
1432: PetscInt econeSize, r, vs, vu;
1434: PetscCall(DMPlexGetConeSize(dm, cone[q], &econeSize));
1435: PetscCall(DMPlexGetCone(dm, cone[q], &econe));
1436: for (r = 0; r < econeSize; ++r) {
1437: PetscCall(PetscFindInt(econe[r], numSplitPoints[dep - 2], splitPoints[dep - 2], &vs));
1438: PetscCall(PetscFindInt(econe[r], numUnsplitPoints[dep - 2], unsplitPoints[dep - 2], &vu));
1439: if (vs >= 0) continue;
1440: PetscCheck(vu >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, econe[r], dep - 2);
1441: hasUnsplit = PETSC_TRUE;
1442: }
1443: }
1444: }
1445: }
1446: PetscCall(DMPlexSetCone(sdm, splitp, &coneNew[2]));
1447: PetscCall(DMPlexSetConeOrientation(sdm, splitp, ornt));
1448: /* Face support */
1449: PetscInt vals[2];
1451: PetscCall(DMLabelGetValue(label, support[0], &vals[0]));
1452: if (supportSize > 1) PetscCall(DMLabelGetValue(label, support[1], &vals[1]));
1453: else vals[1] = -vals[0];
1454: PetscCheck(vals[0] * vals[1] < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid support labels %" PetscInt_FMT " %" PetscInt_FMT, vals[0], vals[1]);
1456: for (s = 0; s < 2; ++s) {
1457: if (s >= supportSize) {
1458: if (vals[s] < 0) {
1459: /* Ghost old face: Replace negative side cell with cohesive cell */
1460: PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell));
1461: } else {
1462: /* Ghost new face: Replace positive side cell with cohesive cell */
1463: PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell));
1464: }
1465: } else {
1466: if (vals[s] < 0) {
1467: /* Split old face: Replace negative side cell with cohesive cell */
1468: PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell));
1469: } else {
1470: /* Split new face: Replace positive side cell with cohesive cell */
1471: PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell));
1472: }
1473: }
1474: }
1475: /* Get orientation for cohesive face using the positive side cell */
1476: {
1477: const PetscInt *ncone, *nconeO;
1478: PetscInt nconeSize, nc, ocell;
1479: PetscBool flip = PETSC_FALSE;
1481: if (supportSize > 1) {
1482: ocell = vals[0] < 0 ? support[1] : support[0];
1483: } else {
1484: ocell = support[0];
1485: flip = vals[0] < 0 ? PETSC_TRUE : PETSC_FALSE;
1486: }
1487: PetscCall(DMPlexGetConeSize(dm, ocell, &nconeSize));
1488: PetscCall(DMPlexGetCone(dm, ocell, &ncone));
1489: PetscCall(DMPlexGetConeOrientation(dm, ocell, &nconeO));
1490: for (nc = 0; nc < nconeSize; ++nc) {
1491: if (ncone[nc] == oldp) {
1492: coneONew[0] = flip ? -(nconeO[nc] + 1) : nconeO[nc];
1493: break;
1494: }
1495: }
1496: PetscCheck(nc < nconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate face %" PetscInt_FMT " in neighboring cell %" PetscInt_FMT, oldp, ocell);
1497: }
1498: /* Cohesive cell: Old and new split face, then new cohesive faces */
1499: {
1500: const PetscInt No = DMPolytopeTypeGetNumArrangments(ct) / 2;
1501: PetscCheck((coneONew[0] >= -No) && (coneONew[0] < No), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid %s orientation %" PetscInt_FMT, DMPolytopeTypes[ct], coneONew[0]);
1502: }
1503: const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, coneONew[0]);
1505: coneNew[0] = newp; /* Extracted negative side orientation above */
1506: coneNew[1] = splitp;
1507: coneONew[1] = coneONew[0];
1508: for (q = 0; q < coneSize; ++q) {
1509: /* Hybrid faces must follow order from oriented end face */
1510: const PetscInt qa = arr[q * 2 + 0];
1511: const PetscInt qo = arr[q * 2 + 1];
1512: DMPolytopeType ft = dep == 2 ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
1514: PetscCall(PetscFindInt(cone[qa], numSplitPoints[dep - 1], splitPoints[dep - 1], &v));
1515: if (v < 0) {
1516: PetscCall(PetscFindInt(cone[qa], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1517: coneNew[2 + q] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1518: } else {
1519: coneNew[2 + q] = v + pMaxNew[dep] + numSplitPoints[dep];
1520: }
1521: coneONew[2 + q] = DMPolytopeTypeComposeOrientation(ft, qo, ornt[qa]);
1522: }
1523: PetscCall(DMPlexSetCone(sdm, hybcell, coneNew));
1524: PetscCall(DMPlexSetConeOrientation(sdm, hybcell, coneONew));
1525: /* Label the hybrid cells on the boundary of the split */
1526: if (hasUnsplit) PetscCall(DMLabelSetValue(label, -hybcell, dim));
1527: } else if (dep == 0) {
1528: const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1530: /* Split old vertex: Edges in old split faces and new cohesive edge */
1531: for (e = 0, qn = 0; e < supportSize; ++e) {
1532: PetscInt val;
1534: PetscCall(DMLabelGetValue(label, support[e], &val));
1535: if ((val == 1) || (val == (shift + 1))) supportNew[qn++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1536: }
1537: supportNew[qn] = hybedge;
1538: PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1539: /* Split new vertex: Edges in new split faces and new cohesive edge */
1540: for (e = 0, qp = 0; e < supportSize; ++e) {
1541: PetscInt val, edge;
1543: PetscCall(DMLabelGetValue(label, support[e], &val));
1544: if (val == 1) {
1545: PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge));
1546: PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]);
1547: supportNew[qp++] = edge + pMaxNew[dep + 1];
1548: } else if (val == -(shift + 1)) {
1549: supportNew[qp++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1550: }
1551: }
1552: supportNew[qp] = hybedge;
1553: PetscCall(DMPlexSetSupport(sdm, splitp, supportNew));
1554: /* Hybrid edge: Old and new split vertex */
1555: coneNew[0] = newp;
1556: coneNew[1] = splitp;
1557: PetscCall(DMPlexSetCone(sdm, hybedge, coneNew));
1558: for (e = 0, qf = 0; e < supportSize; ++e) {
1559: PetscInt val, edge;
1561: PetscCall(DMLabelGetValue(label, support[e], &val));
1562: if (val == 1) {
1563: PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge));
1564: PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]);
1565: supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1566: }
1567: }
1568: PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew));
1569: } else if (dep == dim - 2) {
1570: const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1572: /* Split old edge: old vertices in cone so no change */
1573: /* Split new edge: new vertices in cone */
1574: for (q = 0; q < coneSize; ++q) {
1575: PetscCall(PetscFindInt(cone[q], numSplitPoints[dep - 1], splitPoints[dep - 1], &v));
1576: if (v < 0) {
1577: PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1578: PetscCheck(v >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[q], dep - 1);
1579: coneNew[q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/;
1580: } else {
1581: coneNew[q] = v + pMaxNew[dep - 1];
1582: }
1583: }
1584: PetscCall(DMPlexSetCone(sdm, splitp, coneNew));
1585: /* Split old edge: Faces in positive side cells and old split faces */
1586: for (e = 0, q = 0; e < supportSize; ++e) {
1587: PetscInt val;
1589: PetscCall(DMLabelGetValue(label, support[e], &val));
1590: if (val == dim - 1) {
1591: supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1592: } else if (val == (shift + dim - 1)) {
1593: supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1594: }
1595: }
1596: supportNew[q++] = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1597: PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1598: /* Split new edge: Faces in negative side cells and new split faces */
1599: for (e = 0, q = 0; e < supportSize; ++e) {
1600: PetscInt val, face;
1602: PetscCall(DMLabelGetValue(label, support[e], &val));
1603: if (val == dim - 1) {
1604: PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1605: PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[e]);
1606: supportNew[q++] = face + pMaxNew[dep + 1];
1607: } else if (val == -(shift + dim - 1)) {
1608: supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1609: }
1610: }
1611: supportNew[q++] = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1612: PetscCall(DMPlexSetSupport(sdm, splitp, supportNew));
1613: /* Hybrid face */
1614: coneNew[0] = newp;
1615: coneNew[1] = splitp;
1616: for (v = 0; v < coneSize; ++v) {
1617: PetscInt vertex;
1618: PetscCall(PetscFindInt(cone[v], numSplitPoints[dep - 1], splitPoints[dep - 1], &vertex));
1619: if (vertex < 0) {
1620: PetscCall(PetscFindInt(cone[v], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &vertex));
1621: PetscCheck(vertex >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[v], dep - 1);
1622: coneNew[2 + v] = vertex + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1623: } else {
1624: coneNew[2 + v] = vertex + pMaxNew[dep] + numSplitPoints[dep];
1625: }
1626: }
1627: PetscCall(DMPlexSetCone(sdm, hybface, coneNew));
1628: for (e = 0, qf = 0; e < supportSize; ++e) {
1629: PetscInt val, face;
1631: PetscCall(DMLabelGetValue(label, support[e], &val));
1632: if (val == dim - 1) {
1633: PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1634: PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[e]);
1635: supportNew[qf++] = face + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1636: }
1637: }
1638: PetscCall(DMPlexSetSupport(sdm, hybface, supportNew));
1639: }
1640: }
1641: }
1642: for (dep = 0; dep <= depth; ++dep) {
1643: for (p = 0; p < numUnsplitPoints[dep]; ++p) {
1644: const PetscInt oldp = unsplitPoints[dep][p];
1645: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1646: const PetscInt *cone, *support;
1647: PetscInt coneSize, supportSize, supportSizeNew, q, qf, e, f, s;
1649: PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1650: PetscCall(DMPlexGetCone(dm, oldp, &cone));
1651: PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1652: PetscCall(DMPlexGetSupport(dm, oldp, &support));
1653: if (dep == 0) {
1654: const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];
1656: /* Unsplit vertex */
1657: PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew));
1658: for (s = 0, q = 0; s < supportSize; ++s) {
1659: supportNew[q++] = DMPlexShiftPoint_Internal(support[s], depth, depthShift) /*support[s] + depthOffset[dep+1]*/;
1660: PetscCall(PetscFindInt(support[s], numSplitPoints[dep + 1], splitPoints[dep + 1], &e));
1661: if (e >= 0) supportNew[q++] = e + pMaxNew[dep + 1];
1662: }
1663: supportNew[q++] = hybedge;
1664: supportNew[q++] = hybedge;
1665: PetscCheck(q == supportSizeNew, comm, PETSC_ERR_ARG_WRONG, "Support size %" PetscInt_FMT " != %" PetscInt_FMT " for vertex %" PetscInt_FMT, q, supportSizeNew, newp);
1666: PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1667: /* Hybrid edge */
1668: coneNew[0] = newp;
1669: coneNew[1] = newp;
1670: PetscCall(DMPlexSetCone(sdm, hybedge, coneNew));
1671: for (e = 0, qf = 0; e < supportSize; ++e) {
1672: PetscInt val, edge;
1674: PetscCall(DMLabelGetValue(label, support[e], &val));
1675: if (val == 1) {
1676: PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge));
1677: PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]);
1678: supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1679: } else if (val == (shift2 + 1)) {
1680: PetscCall(PetscFindInt(support[e], numUnsplitPoints[dep + 1], unsplitPoints[dep + 1], &edge));
1681: PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a unsplit edge", support[e]);
1682: supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2] + numSplitPoints[dep + 1];
1683: }
1684: }
1685: PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew));
1686: } else if (dep == dim - 2) {
1687: const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];
1689: /* Unsplit edge: Faces into original edge, split face, and hybrid face twice */
1690: for (f = 0, qf = 0; f < supportSize; ++f) {
1691: PetscInt val, face;
1693: PetscCall(DMLabelGetValue(label, support[f], &val));
1694: if (val == dim - 1) {
1695: PetscCall(PetscFindInt(support[f], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1696: PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[f]);
1697: supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/;
1698: supportNew[qf++] = face + pMaxNew[dep + 1];
1699: } else {
1700: supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/;
1701: }
1702: }
1703: supportNew[qf++] = hybface;
1704: supportNew[qf++] = hybface;
1705: PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew));
1706: PetscCheck(qf == supportSizeNew, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for unsplit edge %" PetscInt_FMT " is %" PetscInt_FMT " != %" PetscInt_FMT, newp, qf, supportSizeNew);
1707: PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1708: /* Add hybrid face */
1709: coneNew[0] = newp;
1710: coneNew[1] = newp;
1711: PetscCall(PetscFindInt(cone[0], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1712: PetscCheck(v >= 0, comm, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is not an unsplit vertex", cone[0]);
1713: coneNew[2] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1714: PetscCall(PetscFindInt(cone[1], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1715: PetscCheck(v >= 0, comm, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is not an unsplit vertex", cone[1]);
1716: coneNew[3] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1717: PetscCall(DMPlexSetCone(sdm, hybface, coneNew));
1718: for (f = 0, qf = 0; f < supportSize; ++f) {
1719: PetscInt val, face;
1721: PetscCall(DMLabelGetValue(label, support[f], &val));
1722: if (val == dim - 1) {
1723: PetscCall(PetscFindInt(support[f], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1724: supportNew[qf++] = face + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1725: }
1726: }
1727: PetscCall(DMPlexGetSupportSize(sdm, hybface, &supportSizeNew));
1728: PetscCheck(qf == supportSizeNew, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for hybrid face %" PetscInt_FMT " is %" PetscInt_FMT " != %" PetscInt_FMT, hybface, qf, supportSizeNew);
1729: PetscCall(DMPlexSetSupport(sdm, hybface, supportNew));
1730: }
1731: }
1732: }
1733: /* Step 6b: Replace split points in negative side cones */
1734: for (sp = 0; sp < numSP; ++sp) {
1735: PetscInt dep = values[sp];
1736: IS pIS;
1737: PetscInt numPoints;
1738: const PetscInt *points;
1740: if (dep >= 0) continue;
1741: PetscCall(DMLabelGetStratumIS(label, dep, &pIS));
1742: if (!pIS) continue;
1743: dep = -dep - shift;
1744: PetscCall(ISGetLocalSize(pIS, &numPoints));
1745: PetscCall(ISGetIndices(pIS, &points));
1746: for (p = 0; p < numPoints; ++p) {
1747: const PetscInt oldp = points[p];
1748: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*depthOffset[dep] + oldp*/;
1749: const PetscInt *cone;
1750: PetscInt coneSize, c;
1751: /* PetscBool replaced = PETSC_FALSE; */
1753: /* Negative edge: replace split vertex */
1754: /* Negative cell: replace split face */
1755: PetscCall(DMPlexGetConeSize(sdm, newp, &coneSize));
1756: PetscCall(DMPlexGetCone(sdm, newp, &cone));
1757: for (c = 0; c < coneSize; ++c) {
1758: const PetscInt coldp = DMPlexShiftPointInverse_Internal(cone[c], depth, depthShift);
1759: PetscInt csplitp, cp, val;
1761: PetscCall(DMLabelGetValue(label, coldp, &val));
1762: if (val == dep - 1) {
1763: PetscCall(PetscFindInt(coldp, numSplitPoints[dep - 1], splitPoints[dep - 1], &cp));
1764: PetscCheck(cp >= 0, comm, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " is not a split point of dimension %" PetscInt_FMT, oldp, dep - 1);
1765: csplitp = pMaxNew[dep - 1] + cp;
1766: PetscCall(DMPlexInsertCone(sdm, newp, c, csplitp));
1767: /* replaced = PETSC_TRUE; */
1768: }
1769: }
1770: /* Cells with only a vertex or edge on the submesh have no replacement */
1771: /* PetscCheck(replaced,comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp); */
1772: }
1773: PetscCall(ISRestoreIndices(pIS, &points));
1774: PetscCall(ISDestroy(&pIS));
1775: }
1776: /* Step 7: Coordinates */
1777: PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, sdm));
1778: PetscCall(DMGetCoordinateSection(sdm, &coordSection));
1779: PetscCall(DMGetCoordinatesLocal(sdm, &coordinates));
1780: PetscCall(VecGetArray(coordinates, &coords));
1781: for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
1782: const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[0][v], depth, depthShift) /*depthOffset[0] + splitPoints[0][v]*/;
1783: const PetscInt splitp = pMaxNew[0] + v;
1784: PetscInt dof, off, soff, d;
1786: PetscCall(PetscSectionGetDof(coordSection, newp, &dof));
1787: PetscCall(PetscSectionGetOffset(coordSection, newp, &off));
1788: PetscCall(PetscSectionGetOffset(coordSection, splitp, &soff));
1789: for (d = 0; d < dof; ++d) coords[soff + d] = coords[off + d];
1790: }
1791: PetscCall(VecRestoreArray(coordinates, &coords));
1792: /* Step 8: SF, if I can figure this out we can split the mesh in parallel */
1793: PetscCall(DMPlexShiftSF_Internal(dm, depthShift, sdm));
1794: /* TODO We need to associate the ghost points with the correct replica */
1795: /* Step 9: Labels */
1796: PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, sdm));
1797: PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_FALSE, sdm));
1798: PetscCall(DMGetNumLabels(sdm, &numLabels));
1799: for (dep = 0; dep <= depth; ++dep) {
1800: for (p = 0; p < numSplitPoints[dep]; ++p) {
1801: const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[dep][p], depth, depthShift) /*depthOffset[dep] + splitPoints[dep][p]*/;
1802: const PetscInt splitp = pMaxNew[dep] + p;
1803: PetscInt l;
1805: if (splitLabel) {
1806: const PetscInt val = 100 + dep;
1808: PetscCall(DMLabelSetValue(splitLabel, newp, val));
1809: PetscCall(DMLabelSetValue(splitLabel, splitp, -val));
1810: }
1811: for (l = 0; l < numLabels; ++l) {
1812: DMLabel mlabel;
1813: const char *lname;
1814: PetscInt val;
1815: PetscBool isDepth;
1817: PetscCall(DMGetLabelName(sdm, l, &lname));
1818: PetscCall(PetscStrcmp(lname, "depth", &isDepth));
1819: if (isDepth) continue;
1820: PetscCall(DMGetLabel(sdm, lname, &mlabel));
1821: PetscCall(DMLabelGetValue(mlabel, newp, &val));
1822: if (val >= 0) PetscCall(DMLabelSetValue(mlabel, splitp, val));
1823: }
1824: }
1825: }
1826: for (sp = 0; sp < numSP; ++sp) {
1827: const PetscInt dep = values[sp];
1829: if ((dep < 0) || (dep > depth)) continue;
1830: if (splitIS[dep]) PetscCall(ISRestoreIndices(splitIS[dep], &splitPoints[dep]));
1831: PetscCall(ISDestroy(&splitIS[dep]));
1832: if (unsplitIS[dep]) PetscCall(ISRestoreIndices(unsplitIS[dep], &unsplitPoints[dep]));
1833: PetscCall(ISDestroy(&unsplitIS[dep]));
1834: }
1835: if (ghostIS) PetscCall(ISRestoreIndices(ghostIS, &ghostPoints));
1836: PetscCall(ISDestroy(&ghostIS));
1837: if (label) {
1838: PetscCall(ISRestoreIndices(valueIS, &values));
1839: PetscCall(ISDestroy(&valueIS));
1840: }
1841: for (d = 0; d <= depth; ++d) {
1842: PetscCall(DMPlexGetDepthStratum(sdm, d, NULL, &pEnd));
1843: pMaxNew[d] = pEnd - numHybridPoints[d] - numHybridPointsOld[d];
1844: }
1845: PetscCall(PetscFree3(coneNew, coneONew, supportNew));
1846: PetscCall(PetscFree5(depthMax, depthEnd, depthShift, pMaxNew, numHybridPointsOld));
1847: PetscCall(PetscFree7(splitIS, unsplitIS, numSplitPoints, numUnsplitPoints, numHybridPoints, splitPoints, unsplitPoints));
1848: PetscFunctionReturn(PETSC_SUCCESS);
1849: }
1851: /*@C
1852: DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
1854: Collective on dm
1856: Input Parameters:
1857: + dm - The original DM
1858: - label - The label specifying the boundary faces (this could be auto-generated)
1860: Output Parameters:
1861: + splitLabel - The label containing the split points, or NULL if no output is desired
1862: - dmSplit - The new DM
1864: Level: developer
1866: .seealso: `DMCreate()`, `DMPlexLabelCohesiveComplete()`
1867: @*/
1868: PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DMLabel splitLabel, DM *dmSplit)
1869: {
1870: DM sdm;
1871: PetscInt dim;
1873: PetscFunctionBegin;
1876: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
1877: PetscCall(DMSetType(sdm, DMPLEX));
1878: PetscCall(DMGetDimension(dm, &dim));
1879: PetscCall(DMSetDimension(sdm, dim));
1880: switch (dim) {
1881: case 2:
1882: case 3:
1883: PetscCall(DMPlexConstructCohesiveCells_Internal(dm, label, splitLabel, sdm));
1884: break;
1885: default:
1886: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %" PetscInt_FMT, dim);
1887: }
1888: *dmSplit = sdm;
1889: PetscFunctionReturn(PETSC_SUCCESS);
1890: }
1892: /* Returns the side of the surface for a given cell with a face on the surface */
1893: static PetscErrorCode GetSurfaceSide_Static(DM dm, DM subdm, PetscInt numSubpoints, const PetscInt *subpoints, PetscInt cell, PetscInt face, PetscBool *pos)
1894: {
1895: const PetscInt *cone, *ornt;
1896: PetscInt dim, coneSize, c;
1898: PetscFunctionBegin;
1899: *pos = PETSC_TRUE;
1900: PetscCall(DMGetDimension(dm, &dim));
1901: PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
1902: PetscCall(DMPlexGetCone(dm, cell, &cone));
1903: PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
1904: for (c = 0; c < coneSize; ++c) {
1905: if (cone[c] == face) {
1906: PetscInt o = ornt[c];
1908: if (subdm) {
1909: const PetscInt *subcone, *subornt;
1910: PetscInt subpoint, subface, subconeSize, sc;
1912: PetscCall(PetscFindInt(cell, numSubpoints, subpoints, &subpoint));
1913: PetscCall(PetscFindInt(face, numSubpoints, subpoints, &subface));
1914: PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize));
1915: PetscCall(DMPlexGetCone(subdm, subpoint, &subcone));
1916: PetscCall(DMPlexGetConeOrientation(subdm, subpoint, &subornt));
1917: for (sc = 0; sc < subconeSize; ++sc) {
1918: if (subcone[sc] == subface) {
1919: o = subornt[0];
1920: break;
1921: }
1922: }
1923: PetscCheck(sc < subconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find subpoint %" PetscInt_FMT " (%" PetscInt_FMT ") in cone for subpoint %" PetscInt_FMT " (%" PetscInt_FMT ")", subface, face, subpoint, cell);
1924: }
1925: if (o >= 0) *pos = PETSC_TRUE;
1926: else *pos = PETSC_FALSE;
1927: break;
1928: }
1929: }
1930: PetscCheck(c != coneSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " in split face %" PetscInt_FMT " support does not have it in the cone", cell, face);
1931: PetscFunctionReturn(PETSC_SUCCESS);
1932: }
1934: static PetscErrorCode CheckFaultEdge_Private(DM dm, DMLabel label)
1935: {
1936: IS facePosIS, faceNegIS, dimIS;
1937: const PetscInt *points;
1938: PetscInt dim, numPoints, p, shift = 100, shift2 = 200;
1940: PetscFunctionBegin;
1941: PetscCall(DMGetDimension(dm, &dim));
1942: /* If any faces touching the fault divide cells on either side, split them */
1943: PetscCall(DMLabelGetStratumIS(label, shift + dim - 1, &facePosIS));
1944: PetscCall(DMLabelGetStratumIS(label, -(shift + dim - 1), &faceNegIS));
1945: if (!facePosIS || !faceNegIS) {
1946: PetscCall(ISDestroy(&facePosIS));
1947: PetscCall(ISDestroy(&faceNegIS));
1948: PetscFunctionReturn(PETSC_SUCCESS);
1949: }
1950: PetscCall(ISExpand(facePosIS, faceNegIS, &dimIS));
1951: PetscCall(ISDestroy(&facePosIS));
1952: PetscCall(ISDestroy(&faceNegIS));
1953: PetscCall(ISGetLocalSize(dimIS, &numPoints));
1954: PetscCall(ISGetIndices(dimIS, &points));
1955: for (p = 0; p < numPoints; ++p) {
1956: const PetscInt point = points[p];
1957: const PetscInt *support;
1958: PetscInt supportSize, valA, valB;
1960: PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
1961: if (supportSize != 2) continue;
1962: PetscCall(DMPlexGetSupport(dm, point, &support));
1963: PetscCall(DMLabelGetValue(label, support[0], &valA));
1964: PetscCall(DMLabelGetValue(label, support[1], &valB));
1965: if ((valA == -1) || (valB == -1)) continue;
1966: if (valA * valB > 0) continue;
1967: /* Check that this face is not incident on only unsplit faces, meaning has at least one split face */
1968: {
1969: PetscInt *closure = NULL;
1970: PetscBool split = PETSC_FALSE;
1971: PetscInt closureSize, cl;
1973: PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
1974: for (cl = 0; cl < closureSize * 2; cl += 2) {
1975: PetscCall(DMLabelGetValue(label, closure[cl], &valA));
1976: if ((valA >= 0) && (valA <= dim)) {
1977: split = PETSC_TRUE;
1978: break;
1979: }
1980: }
1981: PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
1982: if (!split) continue;
1983: }
1984: /* Split the face */
1985: PetscCall(DMLabelGetValue(label, point, &valA));
1986: PetscCall(DMLabelClearValue(label, point, valA));
1987: PetscCall(DMLabelSetValue(label, point, dim - 1));
1988: /* Label its closure:
1989: unmarked: label as unsplit
1990: incident: relabel as split
1991: split: do nothing
1992: */
1993: {
1994: PetscInt *closure = NULL;
1995: PetscInt closureSize, cl, dep;
1997: PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
1998: for (cl = 0; cl < closureSize * 2; cl += 2) {
1999: PetscCall(DMLabelGetValue(label, closure[cl], &valA));
2000: if (valA == -1) { /* Mark as unsplit */
2001: PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep));
2002: PetscCall(DMLabelSetValue(label, closure[cl], shift2 + dep));
2003: } else if (((valA >= shift) && (valA < shift2)) || ((valA <= -shift) && (valA > -shift2))) {
2004: PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep));
2005: PetscCall(DMLabelClearValue(label, closure[cl], valA));
2006: PetscCall(DMLabelSetValue(label, closure[cl], dep));
2007: }
2008: }
2009: PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2010: }
2011: }
2012: PetscCall(ISRestoreIndices(dimIS, &points));
2013: PetscCall(ISDestroy(&dimIS));
2014: PetscFunctionReturn(PETSC_SUCCESS);
2015: }
2017: /*@
2018: DMPlexLabelCohesiveComplete - Starting with a label marking points on an internal surface, we add all other mesh pieces
2019: to complete the surface
2021: Input Parameters:
2022: + dm - The DM
2023: . label - A DMLabel marking the surface
2024: . blabel - A DMLabel marking the vertices on the boundary which will not be duplicated, or NULL to find them automatically
2025: . bvalue - Value of DMLabel marking the vertices on the boundary
2026: . flip - Flag to flip the submesh normal and replace points on the other side
2027: - subdm - The subDM associated with the label, or NULL
2029: Output Parameter:
2030: . label - A DMLabel marking all surface points
2032: Note: The vertices in blabel are called "unsplit" in the terminology from hybrid cell creation.
2034: Level: developer
2036: .seealso: `DMPlexConstructCohesiveCells()`, `DMPlexLabelComplete()`
2037: @*/
2038: PetscErrorCode DMPlexLabelCohesiveComplete(DM dm, DMLabel label, DMLabel blabel, PetscInt bvalue, PetscBool flip, DM subdm)
2039: {
2040: DMLabel depthLabel;
2041: IS dimIS, subpointIS = NULL;
2042: const PetscInt *points, *subpoints;
2043: const PetscInt rev = flip ? -1 : 1;
2044: PetscInt shift = 100, shift2 = 200, shift3 = 300, dim, depth, numPoints, numSubpoints, p, val;
2046: PetscFunctionBegin;
2047: PetscCall(DMPlexGetDepth(dm, &depth));
2048: PetscCall(DMGetDimension(dm, &dim));
2049: PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
2050: if (subdm) {
2051: PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS));
2052: if (subpointIS) {
2053: PetscCall(ISGetLocalSize(subpointIS, &numSubpoints));
2054: PetscCall(ISGetIndices(subpointIS, &subpoints));
2055: }
2056: }
2057: /* Mark cell on the fault, and its faces which touch the fault: cell orientation for face gives the side of the fault */
2058: PetscCall(DMLabelGetStratumIS(label, dim - 1, &dimIS));
2059: if (!dimIS) goto divide;
2060: PetscCall(ISGetLocalSize(dimIS, &numPoints));
2061: PetscCall(ISGetIndices(dimIS, &points));
2062: for (p = 0; p < numPoints; ++p) { /* Loop over fault faces */
2063: const PetscInt *support;
2064: PetscInt supportSize, s;
2066: PetscCall(DMPlexGetSupportSize(dm, points[p], &supportSize));
2067: #if 0
2068: if (supportSize != 2) {
2069: const PetscInt *lp;
2070: PetscInt Nlp, pind;
2072: /* Check that for a cell with a single support face, that face is in the SF */
2073: /* THis check only works for the remote side. We would need root side information */
2074: PetscCall(PetscSFGetGraph(dm->sf, NULL, &Nlp, &lp, NULL));
2075: PetscCall(PetscFindInt(points[p], Nlp, lp, &pind));
2076: PetscCheck(pind >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Split face %" PetscInt_FMT " has %" PetscInt_FMT " != 2 supports, and the face is not shared with another process", points[p], supportSize);
2077: }
2078: #endif
2079: PetscCall(DMPlexGetSupport(dm, points[p], &support));
2080: for (s = 0; s < supportSize; ++s) {
2081: const PetscInt *cone;
2082: PetscInt coneSize, c;
2083: PetscBool pos;
2085: PetscCall(GetSurfaceSide_Static(dm, subdm, numSubpoints, subpoints, support[s], points[p], &pos));
2086: if (pos) PetscCall(DMLabelSetValue(label, support[s], rev * (shift + dim)));
2087: else PetscCall(DMLabelSetValue(label, support[s], -rev * (shift + dim)));
2088: if (rev < 0) pos = !pos ? PETSC_TRUE : PETSC_FALSE;
2089: /* Put faces touching the fault in the label */
2090: PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
2091: PetscCall(DMPlexGetCone(dm, support[s], &cone));
2092: for (c = 0; c < coneSize; ++c) {
2093: const PetscInt point = cone[c];
2095: PetscCall(DMLabelGetValue(label, point, &val));
2096: if (val == -1) {
2097: PetscInt *closure = NULL;
2098: PetscInt closureSize, cl;
2100: PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2101: for (cl = 0; cl < closureSize * 2; cl += 2) {
2102: const PetscInt clp = closure[cl];
2103: PetscInt bval = -1;
2105: PetscCall(DMLabelGetValue(label, clp, &val));
2106: if (blabel) PetscCall(DMLabelGetValue(blabel, clp, &bval));
2107: if ((val >= 0) && (val < dim - 1) && (bval < 0)) {
2108: PetscCall(DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift + dim - 1 : -(shift + dim - 1)));
2109: break;
2110: }
2111: }
2112: PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2113: }
2114: }
2115: }
2116: }
2117: PetscCall(ISRestoreIndices(dimIS, &points));
2118: PetscCall(ISDestroy(&dimIS));
2119: /* Mark boundary points as unsplit */
2120: if (blabel) {
2121: IS bdIS;
2123: PetscCall(DMLabelGetStratumIS(blabel, bvalue, &bdIS));
2124: PetscCall(ISGetLocalSize(bdIS, &numPoints));
2125: PetscCall(ISGetIndices(bdIS, &points));
2126: for (p = 0; p < numPoints; ++p) {
2127: const PetscInt point = points[p];
2128: PetscInt val, bval;
2130: PetscCall(DMLabelGetValue(blabel, point, &bval));
2131: if (bval >= 0) {
2132: PetscCall(DMLabelGetValue(label, point, &val));
2133: if ((val < 0) || (val > dim)) {
2134: /* This could be a point added from splitting a vertex on an adjacent fault, otherwise its just wrong */
2135: PetscCall(DMLabelClearValue(blabel, point, bval));
2136: }
2137: }
2138: }
2139: for (p = 0; p < numPoints; ++p) {
2140: const PetscInt point = points[p];
2141: PetscInt val, bval;
2143: PetscCall(DMLabelGetValue(blabel, point, &bval));
2144: if (bval >= 0) {
2145: const PetscInt *cone, *support;
2146: PetscInt coneSize, supportSize, s, valA, valB, valE;
2148: /* Mark as unsplit */
2149: PetscCall(DMLabelGetValue(label, point, &val));
2150: PetscCheck(val >= 0 && val <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " has label value %" PetscInt_FMT ", should be part of the fault", point, val);
2151: PetscCall(DMLabelClearValue(label, point, val));
2152: PetscCall(DMLabelSetValue(label, point, shift2 + val));
2153: /* Check for cross-edge
2154: A cross-edge has endpoints which are both on the boundary of the surface, but the edge itself is not. */
2155: if (val != 0) continue;
2156: PetscCall(DMPlexGetSupport(dm, point, &support));
2157: PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
2158: for (s = 0; s < supportSize; ++s) {
2159: PetscCall(DMPlexGetCone(dm, support[s], &cone));
2160: PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
2161: PetscCheck(coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %" PetscInt_FMT " has %" PetscInt_FMT " vertices != 2", support[s], coneSize);
2162: PetscCall(DMLabelGetValue(blabel, cone[0], &valA));
2163: PetscCall(DMLabelGetValue(blabel, cone[1], &valB));
2164: PetscCall(DMLabelGetValue(blabel, support[s], &valE));
2165: if ((valE < 0) && (valA >= 0) && (valB >= 0) && (cone[0] != cone[1])) PetscCall(DMLabelSetValue(blabel, support[s], 2));
2166: }
2167: }
2168: }
2169: PetscCall(ISRestoreIndices(bdIS, &points));
2170: PetscCall(ISDestroy(&bdIS));
2171: }
2172: /* Mark ghost fault cells */
2173: {
2174: PetscSF sf;
2175: const PetscInt *leaves;
2176: PetscInt Nl, l;
2178: PetscCall(DMGetPointSF(dm, &sf));
2179: PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
2180: PetscCall(DMLabelGetStratumIS(label, dim - 1, &dimIS));
2181: if (!dimIS) goto divide;
2182: PetscCall(ISGetLocalSize(dimIS, &numPoints));
2183: PetscCall(ISGetIndices(dimIS, &points));
2184: if (Nl > 0) {
2185: for (p = 0; p < numPoints; ++p) {
2186: const PetscInt point = points[p];
2187: PetscInt val;
2189: PetscCall(PetscFindInt(point, Nl, leaves, &l));
2190: if (l >= 0) {
2191: PetscInt *closure = NULL;
2192: PetscInt closureSize, cl;
2194: PetscCall(DMLabelGetValue(label, point, &val));
2195: PetscCheck((val == dim - 1) || (val == shift2 + dim - 1), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " has label value %" PetscInt_FMT ", should be a fault face", point, val);
2196: PetscCall(DMLabelClearValue(label, point, val));
2197: PetscCall(DMLabelSetValue(label, point, shift3 + val));
2198: PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2199: for (cl = 2; cl < closureSize * 2; cl += 2) {
2200: const PetscInt clp = closure[cl];
2202: PetscCall(DMLabelGetValue(label, clp, &val));
2203: PetscCheck(val != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " is missing from label, but is in the closure of a fault face", point);
2204: PetscCall(DMLabelClearValue(label, clp, val));
2205: PetscCall(DMLabelSetValue(label, clp, shift3 + val));
2206: }
2207: PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2208: }
2209: }
2210: }
2211: PetscCall(ISRestoreIndices(dimIS, &points));
2212: PetscCall(ISDestroy(&dimIS));
2213: }
2214: divide:
2215: if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &subpoints));
2216: PetscCall(DMPlexLabelFaultHalo(dm, label));
2217: PetscCall(CheckFaultEdge_Private(dm, label));
2218: PetscFunctionReturn(PETSC_SUCCESS);
2219: }
2221: /* Check that no cell have all vertices on the fault */
2222: PetscErrorCode DMPlexCheckValidSubmesh_Private(DM dm, DMLabel label, DM subdm)
2223: {
2224: IS subpointIS;
2225: const PetscInt *dmpoints;
2226: PetscInt defaultValue, cStart, cEnd, c, vStart, vEnd;
2228: PetscFunctionBegin;
2229: if (!label) PetscFunctionReturn(PETSC_SUCCESS);
2230: PetscCall(DMLabelGetDefaultValue(label, &defaultValue));
2231: PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS));
2232: if (!subpointIS) PetscFunctionReturn(PETSC_SUCCESS);
2233: PetscCall(DMPlexGetHeightStratum(subdm, 0, &cStart, &cEnd));
2234: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2235: PetscCall(ISGetIndices(subpointIS, &dmpoints));
2236: for (c = cStart; c < cEnd; ++c) {
2237: PetscBool invalidCell = PETSC_TRUE;
2238: PetscInt *closure = NULL;
2239: PetscInt closureSize, cl;
2241: PetscCall(DMPlexGetTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure));
2242: for (cl = 0; cl < closureSize * 2; cl += 2) {
2243: PetscInt value = 0;
2245: if ((closure[cl] < vStart) || (closure[cl] >= vEnd)) continue;
2246: PetscCall(DMLabelGetValue(label, closure[cl], &value));
2247: if (value == defaultValue) {
2248: invalidCell = PETSC_FALSE;
2249: break;
2250: }
2251: }
2252: PetscCall(DMPlexRestoreTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure));
2253: if (invalidCell) {
2254: PetscCall(ISRestoreIndices(subpointIS, &dmpoints));
2255: PetscCall(ISDestroy(&subpointIS));
2256: PetscCall(DMDestroy(&subdm));
2257: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ambiguous submesh. Cell %" PetscInt_FMT " has all of its vertices on the submesh.", dmpoints[c]);
2258: }
2259: }
2260: PetscCall(ISRestoreIndices(subpointIS, &dmpoints));
2261: PetscFunctionReturn(PETSC_SUCCESS);
2262: }
2264: /*@
2265: DMPlexCreateHybridMesh - Create a mesh with hybrid cells along an internal interface
2267: Collective on dm
2269: Input Parameters:
2270: + dm - The original DM
2271: . label - The label specifying the interface vertices
2272: . bdlabel - The optional label specifying the interface boundary vertices
2273: - bdvalue - Value of optional label specifying the interface boundary vertices
2275: Output Parameters:
2276: + hybridLabel - The label fully marking the interface, or NULL if no output is desired
2277: . splitLabel - The label containing the split points, or NULL if no output is desired
2278: . dmInterface - The new interface DM, or NULL
2279: - dmHybrid - The new DM with cohesive cells
2281: Note: The hybridLabel indicates what parts of the original mesh impinged on the division surface. For points
2282: directly on the division surface, they are labeled with their dimension, so an edge 7 on the division surface would be
2283: 7 (1) in hybridLabel. For points that impinge from the positive side, they are labeled with 100+dim, so an edge 6 with
2284: one vertex 3 on the surface would be 6 (101) and 3 (0) in hybridLabel. If an edge 9 from the negative side of the
2285: surface also hits vertex 3, it would be 9 (-101) in hybridLabel.
2287: The splitLabel indicates what points in the new hybrid mesh were the result of splitting points in the original
2288: mesh. The label value is $\pm 100+dim$ for each point. For example, if two edges 10 and 14 in the hybrid resulting from
2289: splitting an edge in the original mesh, you would have 10 (101) and 14 (-101) in the splitLabel.
2291: The dmInterface is a DM built from the original division surface. It has a label which can be retrieved using
2292: DMPlexGetSubpointMap() which maps each point back to the point in the surface of the original mesh.
2294: Level: developer
2296: .seealso: `DMPlexConstructCohesiveCells()`, `DMPlexLabelCohesiveComplete()`, `DMPlexGetSubpointMap()`, `DMCreate()`
2297: @*/
2298: PetscErrorCode DMPlexCreateHybridMesh(DM dm, DMLabel label, DMLabel bdlabel, PetscInt bdvalue, DMLabel *hybridLabel, DMLabel *splitLabel, DM *dmInterface, DM *dmHybrid)
2299: {
2300: DM idm;
2301: DMLabel subpointMap, hlabel, slabel = NULL;
2302: PetscInt dim;
2304: PetscFunctionBegin;
2312: PetscCall(DMGetDimension(dm, &dim));
2313: PetscCall(DMPlexCreateSubmesh(dm, label, 1, PETSC_FALSE, &idm));
2314: PetscCall(DMPlexCheckValidSubmesh_Private(dm, label, idm));
2315: PetscCall(DMPlexOrient(idm));
2316: PetscCall(DMPlexGetSubpointMap(idm, &subpointMap));
2317: PetscCall(DMLabelDuplicate(subpointMap, &hlabel));
2318: PetscCall(DMLabelClearStratum(hlabel, dim));
2319: if (splitLabel) {
2320: const char *name;
2321: char sname[PETSC_MAX_PATH_LEN];
2323: PetscCall(PetscObjectGetName((PetscObject)hlabel, &name));
2324: PetscCall(PetscStrncpy(sname, name, PETSC_MAX_PATH_LEN));
2325: PetscCall(PetscStrcat(sname, " split"));
2326: PetscCall(DMLabelCreate(PETSC_COMM_SELF, sname, &slabel));
2327: }
2328: PetscCall(DMPlexLabelCohesiveComplete(dm, hlabel, bdlabel, bdvalue, PETSC_FALSE, idm));
2329: if (dmInterface) {
2330: *dmInterface = idm;
2331: } else PetscCall(DMDestroy(&idm));
2332: PetscCall(DMPlexConstructCohesiveCells(dm, hlabel, slabel, dmHybrid));
2333: PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *dmHybrid));
2334: if (hybridLabel) *hybridLabel = hlabel;
2335: else PetscCall(DMLabelDestroy(&hlabel));
2336: if (splitLabel) *splitLabel = slabel;
2337: {
2338: DM cdm;
2339: DMLabel ctLabel;
2341: /* We need to somehow share the celltype label with the coordinate dm */
2342: PetscCall(DMGetCoordinateDM(*dmHybrid, &cdm));
2343: PetscCall(DMPlexGetCellTypeLabel(*dmHybrid, &ctLabel));
2344: PetscCall(DMSetLabel(cdm, ctLabel));
2345: }
2346: PetscFunctionReturn(PETSC_SUCCESS);
2347: }
2349: /* Here we need the explicit assumption that:
2351: For any marked cell, the marked vertices constitute a single face
2352: */
2353: static PetscErrorCode DMPlexMarkSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, DM subdm)
2354: {
2355: IS subvertexIS = NULL;
2356: const PetscInt *subvertices;
2357: PetscInt *pStart, *pEnd, pSize;
2358: PetscInt depth, dim, d, numSubVerticesInitial = 0, v;
2360: PetscFunctionBegin;
2361: *numFaces = 0;
2362: *nFV = 0;
2363: PetscCall(DMPlexGetDepth(dm, &depth));
2364: PetscCall(DMGetDimension(dm, &dim));
2365: pSize = PetscMax(depth, dim) + 1;
2366: PetscCall(PetscMalloc2(pSize, &pStart, pSize, &pEnd));
2367: for (d = 0; d <= depth; ++d) PetscCall(DMPlexGetSimplexOrBoxCells(dm, depth - d, &pStart[d], &pEnd[d]));
2368: /* Loop over initial vertices and mark all faces in the collective star() */
2369: if (vertexLabel) PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS));
2370: if (subvertexIS) {
2371: PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial));
2372: PetscCall(ISGetIndices(subvertexIS, &subvertices));
2373: }
2374: for (v = 0; v < numSubVerticesInitial; ++v) {
2375: const PetscInt vertex = subvertices[v];
2376: PetscInt *star = NULL;
2377: PetscInt starSize, s, numCells = 0, c;
2379: PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2380: for (s = 0; s < starSize * 2; s += 2) {
2381: const PetscInt point = star[s];
2382: if ((point >= pStart[depth]) && (point < pEnd[depth])) star[numCells++] = point;
2383: }
2384: for (c = 0; c < numCells; ++c) {
2385: const PetscInt cell = star[c];
2386: PetscInt *closure = NULL;
2387: PetscInt closureSize, cl;
2388: PetscInt cellLoc, numCorners = 0, faceSize = 0;
2390: PetscCall(DMLabelGetValue(subpointMap, cell, &cellLoc));
2391: if (cellLoc == 2) continue;
2392: PetscCheck(cellLoc < 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %" PetscInt_FMT " has dimension %" PetscInt_FMT " in the surface label", cell, cellLoc);
2393: PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
2394: for (cl = 0; cl < closureSize * 2; cl += 2) {
2395: const PetscInt point = closure[cl];
2396: PetscInt vertexLoc;
2398: if ((point >= pStart[0]) && (point < pEnd[0])) {
2399: ++numCorners;
2400: PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc));
2401: if (vertexLoc == value) closure[faceSize++] = point;
2402: }
2403: }
2404: if (!(*nFV)) PetscCall(DMPlexGetNumFaceVertices(dm, dim, numCorners, nFV));
2405: PetscCheck(faceSize <= *nFV, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %" PetscInt_FMT " of an element on the surface", faceSize);
2406: if (faceSize == *nFV) {
2407: const PetscInt *cells = NULL;
2408: PetscInt numCells, nc;
2410: ++(*numFaces);
2411: for (cl = 0; cl < faceSize; ++cl) PetscCall(DMLabelSetValue(subpointMap, closure[cl], 0));
2412: PetscCall(DMPlexGetJoin(dm, faceSize, closure, &numCells, &cells));
2413: for (nc = 0; nc < numCells; ++nc) PetscCall(DMLabelSetValue(subpointMap, cells[nc], 2));
2414: PetscCall(DMPlexRestoreJoin(dm, faceSize, closure, &numCells, &cells));
2415: }
2416: PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
2417: }
2418: PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2419: }
2420: if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices));
2421: PetscCall(ISDestroy(&subvertexIS));
2422: PetscCall(PetscFree2(pStart, pEnd));
2423: PetscFunctionReturn(PETSC_SUCCESS);
2424: }
2426: static PetscErrorCode DMPlexMarkSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DMLabel subpointMap, DM subdm)
2427: {
2428: IS subvertexIS = NULL;
2429: const PetscInt *subvertices;
2430: PetscInt *pStart, *pEnd;
2431: PetscInt dim, d, numSubVerticesInitial = 0, v;
2433: PetscFunctionBegin;
2434: PetscCall(DMGetDimension(dm, &dim));
2435: PetscCall(PetscMalloc2(dim + 1, &pStart, dim + 1, &pEnd));
2436: for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetSimplexOrBoxCells(dm, dim - d, &pStart[d], &pEnd[d]));
2437: /* Loop over initial vertices and mark all faces in the collective star() */
2438: if (vertexLabel) {
2439: PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS));
2440: if (subvertexIS) {
2441: PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial));
2442: PetscCall(ISGetIndices(subvertexIS, &subvertices));
2443: }
2444: }
2445: for (v = 0; v < numSubVerticesInitial; ++v) {
2446: const PetscInt vertex = subvertices[v];
2447: PetscInt *star = NULL;
2448: PetscInt starSize, s, numFaces = 0, f;
2450: PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2451: for (s = 0; s < starSize * 2; s += 2) {
2452: const PetscInt point = star[s];
2453: PetscInt faceLoc;
2455: if ((point >= pStart[dim - 1]) && (point < pEnd[dim - 1])) {
2456: if (markedFaces) {
2457: PetscCall(DMLabelGetValue(vertexLabel, point, &faceLoc));
2458: if (faceLoc < 0) continue;
2459: }
2460: star[numFaces++] = point;
2461: }
2462: }
2463: for (f = 0; f < numFaces; ++f) {
2464: const PetscInt face = star[f];
2465: PetscInt *closure = NULL;
2466: PetscInt closureSize, c;
2467: PetscInt faceLoc;
2469: PetscCall(DMLabelGetValue(subpointMap, face, &faceLoc));
2470: if (faceLoc == dim - 1) continue;
2471: PetscCheck(faceLoc < 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %" PetscInt_FMT " has dimension %" PetscInt_FMT " in the surface label", face, faceLoc);
2472: PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure));
2473: for (c = 0; c < closureSize * 2; c += 2) {
2474: const PetscInt point = closure[c];
2475: PetscInt vertexLoc;
2477: if ((point >= pStart[0]) && (point < pEnd[0])) {
2478: PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc));
2479: if (vertexLoc != value) break;
2480: }
2481: }
2482: if (c == closureSize * 2) {
2483: const PetscInt *support;
2484: PetscInt supportSize, s;
2486: for (c = 0; c < closureSize * 2; c += 2) {
2487: const PetscInt point = closure[c];
2489: for (d = 0; d < dim; ++d) {
2490: if ((point >= pStart[d]) && (point < pEnd[d])) {
2491: PetscCall(DMLabelSetValue(subpointMap, point, d));
2492: break;
2493: }
2494: }
2495: }
2496: PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
2497: PetscCall(DMPlexGetSupport(dm, face, &support));
2498: for (s = 0; s < supportSize; ++s) PetscCall(DMLabelSetValue(subpointMap, support[s], dim));
2499: }
2500: PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure));
2501: }
2502: PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2503: }
2504: if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices));
2505: PetscCall(ISDestroy(&subvertexIS));
2506: PetscCall(PetscFree2(pStart, pEnd));
2507: PetscFunctionReturn(PETSC_SUCCESS);
2508: }
2510: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char labelname[], PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, PetscInt *subCells[], DM subdm)
2511: {
2512: DMLabel label = NULL;
2513: const PetscInt *cone;
2514: PetscInt dim, cMax, cEnd, c, subc = 0, p, coneSize = -1;
2516: PetscFunctionBegin;
2517: *numFaces = 0;
2518: *nFV = 0;
2519: if (labelname) PetscCall(DMGetLabel(dm, labelname, &label));
2520: *subCells = NULL;
2521: PetscCall(DMGetDimension(dm, &dim));
2522: PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd));
2523: if (cMax < 0) PetscFunctionReturn(PETSC_SUCCESS);
2524: if (label) {
2525: for (c = cMax; c < cEnd; ++c) {
2526: PetscInt val;
2528: PetscCall(DMLabelGetValue(label, c, &val));
2529: if (val == value) {
2530: ++(*numFaces);
2531: PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
2532: }
2533: }
2534: } else {
2535: *numFaces = cEnd - cMax;
2536: PetscCall(DMPlexGetConeSize(dm, cMax, &coneSize));
2537: }
2538: PetscCall(PetscMalloc1(*numFaces * 2, subCells));
2539: if (!(*numFaces)) PetscFunctionReturn(PETSC_SUCCESS);
2540: *nFV = hasLagrange ? coneSize / 3 : coneSize / 2;
2541: for (c = cMax; c < cEnd; ++c) {
2542: const PetscInt *cells;
2543: PetscInt numCells;
2545: if (label) {
2546: PetscInt val;
2548: PetscCall(DMLabelGetValue(label, c, &val));
2549: if (val != value) continue;
2550: }
2551: PetscCall(DMPlexGetCone(dm, c, &cone));
2552: for (p = 0; p < *nFV; ++p) PetscCall(DMLabelSetValue(subpointMap, cone[p], 0));
2553: /* Negative face */
2554: PetscCall(DMPlexGetJoin(dm, *nFV, cone, &numCells, &cells));
2555: /* Not true in parallel
2556: PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
2557: for (p = 0; p < numCells; ++p) {
2558: PetscCall(DMLabelSetValue(subpointMap, cells[p], 2));
2559: (*subCells)[subc++] = cells[p];
2560: }
2561: PetscCall(DMPlexRestoreJoin(dm, *nFV, cone, &numCells, &cells));
2562: /* Positive face is not included */
2563: }
2564: PetscFunctionReturn(PETSC_SUCCESS);
2565: }
2567: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Interpolated(DM dm, DMLabel label, PetscInt value, DMLabel subpointMap, DM subdm)
2568: {
2569: PetscInt *pStart, *pEnd;
2570: PetscInt dim, cMax, cEnd, c, d;
2572: PetscFunctionBegin;
2573: PetscCall(DMGetDimension(dm, &dim));
2574: PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd));
2575: if (cMax < 0) PetscFunctionReturn(PETSC_SUCCESS);
2576: PetscCall(PetscMalloc2(dim + 1, &pStart, dim + 1, &pEnd));
2577: for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]));
2578: for (c = cMax; c < cEnd; ++c) {
2579: const PetscInt *cone;
2580: PetscInt *closure = NULL;
2581: PetscInt fconeSize, coneSize, closureSize, cl, val;
2583: if (label) {
2584: PetscCall(DMLabelGetValue(label, c, &val));
2585: if (val != value) continue;
2586: }
2587: PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
2588: PetscCall(DMPlexGetCone(dm, c, &cone));
2589: PetscCall(DMPlexGetConeSize(dm, cone[0], &fconeSize));
2590: PetscCheck(coneSize == (fconeSize ? fconeSize : 1) + 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells");
2591: /* Negative face */
2592: PetscCall(DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure));
2593: for (cl = 0; cl < closureSize * 2; cl += 2) {
2594: const PetscInt point = closure[cl];
2596: for (d = 0; d <= dim; ++d) {
2597: if ((point >= pStart[d]) && (point < pEnd[d])) {
2598: PetscCall(DMLabelSetValue(subpointMap, point, d));
2599: break;
2600: }
2601: }
2602: }
2603: PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure));
2604: /* Cells -- positive face is not included */
2605: for (cl = 0; cl < 1; ++cl) {
2606: const PetscInt *support;
2607: PetscInt supportSize, s;
2609: PetscCall(DMPlexGetSupportSize(dm, cone[cl], &supportSize));
2610: /* PetscCheck(supportSize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive faces should separate two cells"); */
2611: PetscCall(DMPlexGetSupport(dm, cone[cl], &support));
2612: for (s = 0; s < supportSize; ++s) PetscCall(DMLabelSetValue(subpointMap, support[s], dim));
2613: }
2614: }
2615: PetscCall(PetscFree2(pStart, pEnd));
2616: PetscFunctionReturn(PETSC_SUCCESS);
2617: }
2619: static PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2620: {
2621: MPI_Comm comm;
2622: PetscBool posOrient = PETSC_FALSE;
2623: const PetscInt debug = 0;
2624: PetscInt cellDim, faceSize, f;
2626: PetscFunctionBegin;
2627: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2628: PetscCall(DMGetDimension(dm, &cellDim));
2629: if (debug) PetscCall(PetscPrintf(comm, "cellDim: %" PetscInt_FMT " numCorners: %" PetscInt_FMT "\n", cellDim, numCorners));
2631: if (cellDim == 1 && numCorners == 2) {
2632: /* Triangle */
2633: faceSize = numCorners - 1;
2634: posOrient = !(oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE;
2635: } else if (cellDim == 2 && numCorners == 3) {
2636: /* Triangle */
2637: faceSize = numCorners - 1;
2638: posOrient = !(oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE;
2639: } else if (cellDim == 3 && numCorners == 4) {
2640: /* Tetrahedron */
2641: faceSize = numCorners - 1;
2642: posOrient = (oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE;
2643: } else if (cellDim == 1 && numCorners == 3) {
2644: /* Quadratic line */
2645: faceSize = 1;
2646: posOrient = PETSC_TRUE;
2647: } else if (cellDim == 2 && numCorners == 4) {
2648: /* Quads */
2649: faceSize = 2;
2650: if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
2651: posOrient = PETSC_TRUE;
2652: } else if ((indices[0] == 3) && (indices[1] == 0)) {
2653: posOrient = PETSC_TRUE;
2654: } else {
2655: if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
2656: posOrient = PETSC_FALSE;
2657: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
2658: }
2659: } else if (cellDim == 2 && numCorners == 6) {
2660: /* Quadratic triangle (I hate this) */
2661: /* Edges are determined by the first 2 vertices (corners of edges) */
2662: const PetscInt faceSizeTri = 3;
2663: PetscInt sortedIndices[3], i, iFace;
2664: PetscBool found = PETSC_FALSE;
2665: PetscInt faceVerticesTriSorted[9] = {
2666: 0, 3, 4, /* bottom */
2667: 1, 4, 5, /* right */
2668: 2, 3, 5, /* left */
2669: };
2670: PetscInt faceVerticesTri[9] = {
2671: 0, 3, 4, /* bottom */
2672: 1, 4, 5, /* right */
2673: 2, 5, 3, /* left */
2674: };
2676: for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
2677: PetscCall(PetscSortInt(faceSizeTri, sortedIndices));
2678: for (iFace = 0; iFace < 3; ++iFace) {
2679: const PetscInt ii = iFace * faceSizeTri;
2680: PetscInt fVertex, cVertex;
2682: if ((sortedIndices[0] == faceVerticesTriSorted[ii + 0]) && (sortedIndices[1] == faceVerticesTriSorted[ii + 1])) {
2683: for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
2684: for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
2685: if (indices[cVertex] == faceVerticesTri[ii + fVertex]) {
2686: faceVertices[fVertex] = origVertices[cVertex];
2687: break;
2688: }
2689: }
2690: }
2691: found = PETSC_TRUE;
2692: break;
2693: }
2694: }
2695: PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
2696: if (posOriented) *posOriented = PETSC_TRUE;
2697: PetscFunctionReturn(PETSC_SUCCESS);
2698: } else if (cellDim == 2 && numCorners == 9) {
2699: /* Quadratic quad (I hate this) */
2700: /* Edges are determined by the first 2 vertices (corners of edges) */
2701: const PetscInt faceSizeQuad = 3;
2702: PetscInt sortedIndices[3], i, iFace;
2703: PetscBool found = PETSC_FALSE;
2704: PetscInt faceVerticesQuadSorted[12] = {
2705: 0, 1, 4, /* bottom */
2706: 1, 2, 5, /* right */
2707: 2, 3, 6, /* top */
2708: 0, 3, 7, /* left */
2709: };
2710: PetscInt faceVerticesQuad[12] = {
2711: 0, 1, 4, /* bottom */
2712: 1, 2, 5, /* right */
2713: 2, 3, 6, /* top */
2714: 3, 0, 7, /* left */
2715: };
2717: for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
2718: PetscCall(PetscSortInt(faceSizeQuad, sortedIndices));
2719: for (iFace = 0; iFace < 4; ++iFace) {
2720: const PetscInt ii = iFace * faceSizeQuad;
2721: PetscInt fVertex, cVertex;
2723: if ((sortedIndices[0] == faceVerticesQuadSorted[ii + 0]) && (sortedIndices[1] == faceVerticesQuadSorted[ii + 1])) {
2724: for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
2725: for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
2726: if (indices[cVertex] == faceVerticesQuad[ii + fVertex]) {
2727: faceVertices[fVertex] = origVertices[cVertex];
2728: break;
2729: }
2730: }
2731: }
2732: found = PETSC_TRUE;
2733: break;
2734: }
2735: }
2736: PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
2737: if (posOriented) *posOriented = PETSC_TRUE;
2738: PetscFunctionReturn(PETSC_SUCCESS);
2739: } else if (cellDim == 3 && numCorners == 8) {
2740: /* Hexes
2741: A hex is two oriented quads with the normal of the first
2742: pointing up at the second.
2744: 7---6
2745: /| /|
2746: 4---5 |
2747: | 1-|-2
2748: |/ |/
2749: 0---3
2751: Faces are determined by the first 4 vertices (corners of faces) */
2752: const PetscInt faceSizeHex = 4;
2753: PetscInt sortedIndices[4], i, iFace;
2754: PetscBool found = PETSC_FALSE;
2755: PetscInt faceVerticesHexSorted[24] = {
2756: 0, 1, 2, 3, /* bottom */
2757: 4, 5, 6, 7, /* top */
2758: 0, 3, 4, 5, /* front */
2759: 2, 3, 5, 6, /* right */
2760: 1, 2, 6, 7, /* back */
2761: 0, 1, 4, 7, /* left */
2762: };
2763: PetscInt faceVerticesHex[24] = {
2764: 1, 2, 3, 0, /* bottom */
2765: 4, 5, 6, 7, /* top */
2766: 0, 3, 5, 4, /* front */
2767: 3, 2, 6, 5, /* right */
2768: 2, 1, 7, 6, /* back */
2769: 1, 0, 4, 7, /* left */
2770: };
2772: for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
2773: PetscCall(PetscSortInt(faceSizeHex, sortedIndices));
2774: for (iFace = 0; iFace < 6; ++iFace) {
2775: const PetscInt ii = iFace * faceSizeHex;
2776: PetscInt fVertex, cVertex;
2778: if ((sortedIndices[0] == faceVerticesHexSorted[ii + 0]) && (sortedIndices[1] == faceVerticesHexSorted[ii + 1]) && (sortedIndices[2] == faceVerticesHexSorted[ii + 2]) && (sortedIndices[3] == faceVerticesHexSorted[ii + 3])) {
2779: for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
2780: for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
2781: if (indices[cVertex] == faceVerticesHex[ii + fVertex]) {
2782: faceVertices[fVertex] = origVertices[cVertex];
2783: break;
2784: }
2785: }
2786: }
2787: found = PETSC_TRUE;
2788: break;
2789: }
2790: }
2791: PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2792: if (posOriented) *posOriented = PETSC_TRUE;
2793: PetscFunctionReturn(PETSC_SUCCESS);
2794: } else if (cellDim == 3 && numCorners == 10) {
2795: /* Quadratic tet */
2796: /* Faces are determined by the first 3 vertices (corners of faces) */
2797: const PetscInt faceSizeTet = 6;
2798: PetscInt sortedIndices[6], i, iFace;
2799: PetscBool found = PETSC_FALSE;
2800: PetscInt faceVerticesTetSorted[24] = {
2801: 0, 1, 2, 6, 7, 8, /* bottom */
2802: 0, 3, 4, 6, 7, 9, /* front */
2803: 1, 4, 5, 7, 8, 9, /* right */
2804: 2, 3, 5, 6, 8, 9, /* left */
2805: };
2806: PetscInt faceVerticesTet[24] = {
2807: 0, 1, 2, 6, 7, 8, /* bottom */
2808: 0, 4, 3, 6, 7, 9, /* front */
2809: 1, 5, 4, 7, 8, 9, /* right */
2810: 2, 3, 5, 8, 6, 9, /* left */
2811: };
2813: for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
2814: PetscCall(PetscSortInt(faceSizeTet, sortedIndices));
2815: for (iFace = 0; iFace < 4; ++iFace) {
2816: const PetscInt ii = iFace * faceSizeTet;
2817: PetscInt fVertex, cVertex;
2819: if ((sortedIndices[0] == faceVerticesTetSorted[ii + 0]) && (sortedIndices[1] == faceVerticesTetSorted[ii + 1]) && (sortedIndices[2] == faceVerticesTetSorted[ii + 2]) && (sortedIndices[3] == faceVerticesTetSorted[ii + 3])) {
2820: for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
2821: for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
2822: if (indices[cVertex] == faceVerticesTet[ii + fVertex]) {
2823: faceVertices[fVertex] = origVertices[cVertex];
2824: break;
2825: }
2826: }
2827: }
2828: found = PETSC_TRUE;
2829: break;
2830: }
2831: }
2832: PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
2833: if (posOriented) *posOriented = PETSC_TRUE;
2834: PetscFunctionReturn(PETSC_SUCCESS);
2835: } else if (cellDim == 3 && numCorners == 27) {
2836: /* Quadratic hexes (I hate this)
2837: A hex is two oriented quads with the normal of the first
2838: pointing up at the second.
2840: 7---6
2841: /| /|
2842: 4---5 |
2843: | 3-|-2
2844: |/ |/
2845: 0---1
2847: Faces are determined by the first 4 vertices (corners of faces) */
2848: const PetscInt faceSizeQuadHex = 9;
2849: PetscInt sortedIndices[9], i, iFace;
2850: PetscBool found = PETSC_FALSE;
2851: PetscInt faceVerticesQuadHexSorted[54] = {
2852: 0, 1, 2, 3, 8, 9, 10, 11, 24, /* bottom */
2853: 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */
2854: 0, 1, 4, 5, 8, 12, 16, 17, 22, /* front */
2855: 1, 2, 5, 6, 9, 13, 17, 18, 21, /* right */
2856: 2, 3, 6, 7, 10, 14, 18, 19, 23, /* back */
2857: 0, 3, 4, 7, 11, 15, 16, 19, 20, /* left */
2858: };
2859: PetscInt faceVerticesQuadHex[54] = {
2860: 3, 2, 1, 0, 10, 9, 8, 11, 24, /* bottom */
2861: 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */
2862: 0, 1, 5, 4, 8, 17, 12, 16, 22, /* front */
2863: 1, 2, 6, 5, 9, 18, 13, 17, 21, /* right */
2864: 2, 3, 7, 6, 10, 19, 14, 18, 23, /* back */
2865: 3, 0, 4, 7, 11, 16, 15, 19, 20 /* left */
2866: };
2868: for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
2869: PetscCall(PetscSortInt(faceSizeQuadHex, sortedIndices));
2870: for (iFace = 0; iFace < 6; ++iFace) {
2871: const PetscInt ii = iFace * faceSizeQuadHex;
2872: PetscInt fVertex, cVertex;
2874: if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii + 0]) && (sortedIndices[1] == faceVerticesQuadHexSorted[ii + 1]) && (sortedIndices[2] == faceVerticesQuadHexSorted[ii + 2]) && (sortedIndices[3] == faceVerticesQuadHexSorted[ii + 3])) {
2875: for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
2876: for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
2877: if (indices[cVertex] == faceVerticesQuadHex[ii + fVertex]) {
2878: faceVertices[fVertex] = origVertices[cVertex];
2879: break;
2880: }
2881: }
2882: }
2883: found = PETSC_TRUE;
2884: break;
2885: }
2886: }
2887: PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2888: if (posOriented) *posOriented = PETSC_TRUE;
2889: PetscFunctionReturn(PETSC_SUCCESS);
2890: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
2891: if (!posOrient) {
2892: if (debug) PetscCall(PetscPrintf(comm, " Reversing initial face orientation\n"));
2893: for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize - 1 - f];
2894: } else {
2895: if (debug) PetscCall(PetscPrintf(comm, " Keeping initial face orientation\n"));
2896: for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
2897: }
2898: if (posOriented) *posOriented = posOrient;
2899: PetscFunctionReturn(PETSC_SUCCESS);
2900: }
2902: /*@
2903: DMPlexGetOrientedFace - Given a cell and a face, as a set of vertices, return the oriented face, as a set of vertices,
2904: in faceVertices. The orientation is such that the face normal points out of the cell
2906: Not collective
2908: Input Parameters:
2909: + dm - The original mesh
2910: . cell - The cell mesh point
2911: . faceSize - The number of vertices on the face
2912: . face - The face vertices
2913: . numCorners - The number of vertices on the cell
2914: . indices - Local numbering of face vertices in cell cone
2915: - origVertices - Original face vertices
2917: Output Parameters:
2918: + faceVertices - The face vertices properly oriented
2919: - posOriented - PETSC_TRUE if the face was oriented with outward normal
2921: Level: developer
2923: .seealso: `DMPlexGetCone()`
2924: @*/
2925: PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2926: {
2927: const PetscInt *cone = NULL;
2928: PetscInt coneSize, v, f, v2;
2929: PetscInt oppositeVertex = -1;
2931: PetscFunctionBegin;
2932: PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
2933: PetscCall(DMPlexGetCone(dm, cell, &cone));
2934: for (v = 0, v2 = 0; v < coneSize; ++v) {
2935: PetscBool found = PETSC_FALSE;
2937: for (f = 0; f < faceSize; ++f) {
2938: if (face[f] == cone[v]) {
2939: found = PETSC_TRUE;
2940: break;
2941: }
2942: }
2943: if (found) {
2944: indices[v2] = v;
2945: origVertices[v2] = cone[v];
2946: ++v2;
2947: } else {
2948: oppositeVertex = v;
2949: }
2950: }
2951: PetscCall(DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented));
2952: PetscFunctionReturn(PETSC_SUCCESS);
2953: }
2955: /*
2956: DMPlexInsertFace_Internal - Puts a face into the mesh
2958: Not collective
2960: Input Parameters:
2961: + dm - The DMPlex
2962: . numFaceVertex - The number of vertices in the face
2963: . faceVertices - The vertices in the face for dm
2964: . subfaceVertices - The vertices in the face for subdm
2965: . numCorners - The number of vertices in the cell
2966: . cell - A cell in dm containing the face
2967: . subcell - A cell in subdm containing the face
2968: . firstFace - First face in the mesh
2969: - newFacePoint - Next face in the mesh
2971: Output Parameters:
2972: . newFacePoint - Contains next face point number on input, updated on output
2974: Level: developer
2975: */
2976: static PetscErrorCode DMPlexInsertFace_Internal(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint)
2977: {
2978: MPI_Comm comm;
2979: DM_Plex *submesh = (DM_Plex *)subdm->data;
2980: const PetscInt *faces;
2981: PetscInt numFaces, coneSize;
2983: PetscFunctionBegin;
2984: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2985: PetscCall(DMPlexGetConeSize(subdm, subcell, &coneSize));
2986: PetscCheck(coneSize == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %" PetscInt_FMT " is %" PetscInt_FMT " != 1", cell, coneSize);
2987: #if 0
2988: /* Cannot use this because support() has not been constructed yet */
2989: PetscCall(DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces));
2990: #else
2991: {
2992: PetscInt f;
2994: numFaces = 0;
2995: PetscCall(DMGetWorkArray(subdm, 1, MPIU_INT, (void **)&faces));
2996: for (f = firstFace; f < *newFacePoint; ++f) {
2997: PetscInt dof, off, d;
2999: PetscCall(PetscSectionGetDof(submesh->coneSection, f, &dof));
3000: PetscCall(PetscSectionGetOffset(submesh->coneSection, f, &off));
3001: /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
3002: for (d = 0; d < dof; ++d) {
3003: const PetscInt p = submesh->cones[off + d];
3004: PetscInt v;
3006: for (v = 0; v < numFaceVertices; ++v) {
3007: if (subfaceVertices[v] == p) break;
3008: }
3009: if (v == numFaceVertices) break;
3010: }
3011: if (d == dof) {
3012: numFaces = 1;
3013: ((PetscInt *)faces)[0] = f;
3014: }
3015: }
3016: }
3017: #endif
3018: PetscCheck(numFaces <= 1, comm, PETSC_ERR_ARG_WRONG, "Vertex set had %" PetscInt_FMT " faces, not one", numFaces);
3019: if (numFaces == 1) {
3020: /* Add the other cell neighbor for this face */
3021: PetscCall(DMPlexSetCone(subdm, subcell, faces));
3022: } else {
3023: PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
3024: PetscBool posOriented;
3026: PetscCall(DMGetWorkArray(subdm, 4 * numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices));
3027: origVertices = &orientedVertices[numFaceVertices];
3028: indices = &orientedVertices[numFaceVertices * 2];
3029: orientedSubVertices = &orientedVertices[numFaceVertices * 3];
3030: PetscCall(DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented));
3031: /* TODO: I know that routine should return a permutation, not the indices */
3032: for (v = 0; v < numFaceVertices; ++v) {
3033: const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
3034: for (ov = 0; ov < numFaceVertices; ++ov) {
3035: if (orientedVertices[ov] == vertex) {
3036: orientedSubVertices[ov] = subvertex;
3037: break;
3038: }
3039: }
3040: PetscCheck(ov != numFaceVertices, comm, PETSC_ERR_PLIB, "Could not find face vertex %" PetscInt_FMT " in orientated set", vertex);
3041: }
3042: PetscCall(DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices));
3043: PetscCall(DMPlexSetCone(subdm, subcell, newFacePoint));
3044: PetscCall(DMRestoreWorkArray(subdm, 4 * numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices));
3045: ++(*newFacePoint);
3046: }
3047: #if 0
3048: PetscCall(DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces));
3049: #else
3050: PetscCall(DMRestoreWorkArray(subdm, 1, MPIU_INT, (void **)&faces));
3051: #endif
3052: PetscFunctionReturn(PETSC_SUCCESS);
3053: }
3055: static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm)
3056: {
3057: MPI_Comm comm;
3058: DMLabel subpointMap;
3059: IS subvertexIS, subcellIS;
3060: const PetscInt *subVertices, *subCells;
3061: PetscInt numSubVertices, firstSubVertex, numSubCells;
3062: PetscInt *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0;
3063: PetscInt vStart, vEnd, c, f;
3065: PetscFunctionBegin;
3066: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3067: /* Create subpointMap which marks the submesh */
3068: PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap));
3069: PetscCall(DMPlexSetSubpointMap(subdm, subpointMap));
3070: PetscCall(DMLabelDestroy(&subpointMap));
3071: if (vertexLabel) PetscCall(DMPlexMarkSubmesh_Uninterpolated(dm, vertexLabel, value, subpointMap, &numSubFaces, &nFV, subdm));
3072: /* Setup chart */
3073: PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices));
3074: PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells));
3075: PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices));
3076: PetscCall(DMPlexSetVTKCellHeight(subdm, 1));
3077: /* Set cone sizes */
3078: firstSubVertex = numSubCells;
3079: firstSubFace = numSubCells + numSubVertices;
3080: newFacePoint = firstSubFace;
3081: PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS));
3082: if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices));
3083: PetscCall(DMLabelGetStratumIS(subpointMap, 2, &subcellIS));
3084: if (subcellIS) PetscCall(ISGetIndices(subcellIS, &subCells));
3085: for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1));
3086: for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV));
3087: PetscCall(DMSetUp(subdm));
3088: /* Create face cones */
3089: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3090: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
3091: PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3092: for (c = 0; c < numSubCells; ++c) {
3093: const PetscInt cell = subCells[c];
3094: const PetscInt subcell = c;
3095: PetscInt *closure = NULL;
3096: PetscInt closureSize, cl, numCorners = 0, faceSize = 0;
3098: PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
3099: for (cl = 0; cl < closureSize * 2; cl += 2) {
3100: const PetscInt point = closure[cl];
3101: PetscInt subVertex;
3103: if ((point >= vStart) && (point < vEnd)) {
3104: ++numCorners;
3105: PetscCall(PetscFindInt(point, numSubVertices, subVertices, &subVertex));
3106: if (subVertex >= 0) {
3107: closure[faceSize] = point;
3108: subface[faceSize] = firstSubVertex + subVertex;
3109: ++faceSize;
3110: }
3111: }
3112: }
3113: PetscCheck(faceSize <= nFV, comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %" PetscInt_FMT " of an element on the surface", faceSize);
3114: if (faceSize == nFV) PetscCall(DMPlexInsertFace_Internal(dm, subdm, faceSize, closure, subface, numCorners, cell, subcell, firstSubFace, &newFacePoint));
3115: PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
3116: }
3117: PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3118: PetscCall(DMPlexSymmetrize(subdm));
3119: PetscCall(DMPlexStratify(subdm));
3120: /* Build coordinates */
3121: {
3122: PetscSection coordSection, subCoordSection;
3123: Vec coordinates, subCoordinates;
3124: PetscScalar *coords, *subCoords;
3125: PetscInt numComp, coordSize, v;
3126: const char *name;
3128: PetscCall(DMGetCoordinateSection(dm, &coordSection));
3129: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3130: PetscCall(DMGetCoordinateSection(subdm, &subCoordSection));
3131: PetscCall(PetscSectionSetNumFields(subCoordSection, 1));
3132: PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp));
3133: PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp));
3134: PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices));
3135: for (v = 0; v < numSubVertices; ++v) {
3136: const PetscInt vertex = subVertices[v];
3137: const PetscInt subvertex = firstSubVertex + v;
3138: PetscInt dof;
3140: PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3141: PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof));
3142: PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof));
3143: }
3144: PetscCall(PetscSectionSetUp(subCoordSection));
3145: PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize));
3146: PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates));
3147: PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
3148: PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name));
3149: PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE));
3150: PetscCall(VecSetType(subCoordinates, VECSTANDARD));
3151: if (coordSize) {
3152: PetscCall(VecGetArray(coordinates, &coords));
3153: PetscCall(VecGetArray(subCoordinates, &subCoords));
3154: for (v = 0; v < numSubVertices; ++v) {
3155: const PetscInt vertex = subVertices[v];
3156: const PetscInt subvertex = firstSubVertex + v;
3157: PetscInt dof, off, sdof, soff, d;
3159: PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3160: PetscCall(PetscSectionGetOffset(coordSection, vertex, &off));
3161: PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof));
3162: PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff));
3163: PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof);
3164: for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d];
3165: }
3166: PetscCall(VecRestoreArray(coordinates, &coords));
3167: PetscCall(VecRestoreArray(subCoordinates, &subCoords));
3168: }
3169: PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates));
3170: PetscCall(VecDestroy(&subCoordinates));
3171: }
3172: /* Cleanup */
3173: if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices));
3174: PetscCall(ISDestroy(&subvertexIS));
3175: if (subcellIS) PetscCall(ISRestoreIndices(subcellIS, &subCells));
3176: PetscCall(ISDestroy(&subcellIS));
3177: PetscFunctionReturn(PETSC_SUCCESS);
3178: }
3180: /* TODO: Fix this to properly propagate up error conditions it may find */
3181: static inline PetscInt DMPlexFilterPoint_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[])
3182: {
3183: PetscInt subPoint;
3184: PetscErrorCode ierr;
3186: ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint);
3187: if (ierr) return -1;
3188: return subPoint < 0 ? subPoint : firstSubPoint + subPoint;
3189: }
3191: /* TODO: Fix this to properly propagate up error conditions it may find */
3192: static inline PetscInt DMPlexFilterPointPerm_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[], const PetscInt subIndices[])
3193: {
3194: PetscInt subPoint;
3195: PetscErrorCode ierr;
3197: ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint);
3198: if (ierr) return -1;
3199: return subPoint < 0 ? subPoint : firstSubPoint + (subIndices ? subIndices[subPoint] : subPoint);
3200: }
3202: static PetscErrorCode DMPlexFilterLabels_Internal(DM dm, const PetscInt numSubPoints[], const PetscInt *subpoints[], const PetscInt firstSubPoint[], DM subdm)
3203: {
3204: DMLabel depthLabel;
3205: PetscInt Nl, l, d;
3207: PetscFunctionBegin;
3208: // Reset depth label for fast lookup
3209: PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
3210: PetscCall(DMLabelMakeAllInvalid_Internal(depthLabel));
3211: PetscCall(DMGetNumLabels(dm, &Nl));
3212: for (l = 0; l < Nl; ++l) {
3213: DMLabel label, newlabel;
3214: const char *lname;
3215: PetscBool isDepth, isDim, isCelltype, isVTK;
3216: IS valueIS;
3217: const PetscInt *values;
3218: PetscInt Nv, v;
3220: PetscCall(DMGetLabelName(dm, l, &lname));
3221: PetscCall(PetscStrcmp(lname, "depth", &isDepth));
3222: PetscCall(PetscStrcmp(lname, "dim", &isDim));
3223: PetscCall(PetscStrcmp(lname, "celltype", &isCelltype));
3224: PetscCall(PetscStrcmp(lname, "vtk", &isVTK));
3225: if (isDepth || isDim || isCelltype || isVTK) continue;
3226: PetscCall(DMCreateLabel(subdm, lname));
3227: PetscCall(DMGetLabel(dm, lname, &label));
3228: PetscCall(DMGetLabel(subdm, lname, &newlabel));
3229: PetscCall(DMLabelGetDefaultValue(label, &v));
3230: PetscCall(DMLabelSetDefaultValue(newlabel, v));
3231: PetscCall(DMLabelGetValueIS(label, &valueIS));
3232: PetscCall(ISGetLocalSize(valueIS, &Nv));
3233: PetscCall(ISGetIndices(valueIS, &values));
3234: for (v = 0; v < Nv; ++v) {
3235: IS pointIS;
3236: const PetscInt *points;
3237: PetscInt Np, p;
3239: PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
3240: PetscCall(ISGetLocalSize(pointIS, &Np));
3241: PetscCall(ISGetIndices(pointIS, &points));
3242: for (p = 0; p < Np; ++p) {
3243: const PetscInt point = points[p];
3244: PetscInt subp;
3246: PetscCall(DMPlexGetPointDepth(dm, point, &d));
3247: subp = DMPlexFilterPoint_Internal(point, firstSubPoint[d], numSubPoints[d], subpoints[d]);
3248: if (subp >= 0) PetscCall(DMLabelSetValue(newlabel, subp, values[v]));
3249: }
3250: PetscCall(ISRestoreIndices(pointIS, &points));
3251: PetscCall(ISDestroy(&pointIS));
3252: }
3253: PetscCall(ISRestoreIndices(valueIS, &values));
3254: PetscCall(ISDestroy(&valueIS));
3255: }
3256: PetscFunctionReturn(PETSC_SUCCESS);
3257: }
3259: static PetscErrorCode DMPlexCreateSubmeshGeneric_Interpolated(DM dm, DMLabel label, PetscInt value, PetscBool markedFaces, PetscBool isCohesive, PetscInt cellHeight, DM subdm)
3260: {
3261: MPI_Comm comm;
3262: DMLabel subpointMap;
3263: IS *subpointIS;
3264: const PetscInt **subpoints;
3265: PetscInt *numSubPoints, *firstSubPoint, *coneNew, *orntNew;
3266: PetscInt totSubPoints = 0, maxConeSize, dim, sdim, cdim, p, d, v;
3267: PetscMPIInt rank;
3269: PetscFunctionBegin;
3270: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3271: PetscCallMPI(MPI_Comm_rank(comm, &rank));
3272: /* Create subpointMap which marks the submesh */
3273: PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap));
3274: PetscCall(DMPlexSetSubpointMap(subdm, subpointMap));
3275: if (cellHeight) {
3276: if (isCohesive) PetscCall(DMPlexMarkCohesiveSubmesh_Interpolated(dm, label, value, subpointMap, subdm));
3277: else PetscCall(DMPlexMarkSubmesh_Interpolated(dm, label, value, markedFaces, subpointMap, subdm));
3278: } else {
3279: DMLabel depth;
3280: IS pointIS;
3281: const PetscInt *points;
3282: PetscInt numPoints = 0;
3284: PetscCall(DMPlexGetDepthLabel(dm, &depth));
3285: PetscCall(DMLabelGetStratumIS(label, value, &pointIS));
3286: if (pointIS) {
3287: PetscCall(ISGetIndices(pointIS, &points));
3288: PetscCall(ISGetLocalSize(pointIS, &numPoints));
3289: }
3290: for (p = 0; p < numPoints; ++p) {
3291: PetscInt *closure = NULL;
3292: PetscInt closureSize, c, pdim;
3294: PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
3295: for (c = 0; c < closureSize * 2; c += 2) {
3296: PetscCall(DMLabelGetValue(depth, closure[c], &pdim));
3297: PetscCall(DMLabelSetValue(subpointMap, closure[c], pdim));
3298: }
3299: PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
3300: }
3301: if (pointIS) PetscCall(ISRestoreIndices(pointIS, &points));
3302: PetscCall(ISDestroy(&pointIS));
3303: }
3304: /* Setup chart */
3305: PetscCall(DMGetDimension(dm, &dim));
3306: PetscCall(DMGetCoordinateDim(dm, &cdim));
3307: PetscCall(PetscMalloc4(dim + 1, &numSubPoints, dim + 1, &firstSubPoint, dim + 1, &subpointIS, dim + 1, &subpoints));
3308: for (d = 0; d <= dim; ++d) {
3309: PetscCall(DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d]));
3310: totSubPoints += numSubPoints[d];
3311: }
3312: // Determine submesh dimension
3313: PetscCall(DMGetDimension(subdm, &sdim));
3314: if (sdim > 0) {
3315: // Calling function knows what dimension to use, and we include neighboring cells as well
3316: sdim = dim;
3317: } else {
3318: // We reset the subdimension based on what is being selected
3319: PetscInt lsdim;
3320: for (lsdim = dim; lsdim >= 0; --lsdim)
3321: if (numSubPoints[lsdim]) break;
3322: PetscCallMPI(MPI_Allreduce(&lsdim, &sdim, 1, MPIU_INT, MPIU_MAX, comm));
3323: PetscCall(DMSetDimension(subdm, sdim));
3324: PetscCall(DMSetCoordinateDim(subdm, cdim));
3325: }
3326: PetscCall(DMPlexSetChart(subdm, 0, totSubPoints));
3327: PetscCall(DMPlexSetVTKCellHeight(subdm, cellHeight));
3328: /* Set cone sizes */
3329: firstSubPoint[sdim] = 0;
3330: firstSubPoint[0] = firstSubPoint[sdim] + numSubPoints[sdim];
3331: if (sdim > 1) firstSubPoint[sdim - 1] = firstSubPoint[0] + numSubPoints[0];
3332: if (sdim > 2) firstSubPoint[sdim - 2] = firstSubPoint[sdim - 1] + numSubPoints[sdim - 1];
3333: for (d = 0; d <= sdim; ++d) {
3334: PetscCall(DMLabelGetStratumIS(subpointMap, d, &subpointIS[d]));
3335: if (subpointIS[d]) PetscCall(ISGetIndices(subpointIS[d], &subpoints[d]));
3336: }
3337: /* We do not want this label automatically computed, instead we compute it here */
3338: PetscCall(DMCreateLabel(subdm, "celltype"));
3339: for (d = 0; d <= sdim; ++d) {
3340: for (p = 0; p < numSubPoints[d]; ++p) {
3341: const PetscInt point = subpoints[d][p];
3342: const PetscInt subpoint = firstSubPoint[d] + p;
3343: const PetscInt *cone;
3344: PetscInt coneSize;
3346: PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
3347: if (cellHeight && (d == sdim)) {
3348: PetscInt coneSizeNew, c, val;
3350: PetscCall(DMPlexGetCone(dm, point, &cone));
3351: for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
3352: PetscCall(DMLabelGetValue(subpointMap, cone[c], &val));
3353: if (val >= 0) coneSizeNew++;
3354: }
3355: PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSizeNew));
3356: PetscCall(DMPlexSetCellType(subdm, subpoint, DM_POLYTOPE_FV_GHOST));
3357: } else {
3358: DMPolytopeType ct;
3360: PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSize));
3361: PetscCall(DMPlexGetCellType(dm, point, &ct));
3362: PetscCall(DMPlexSetCellType(subdm, subpoint, ct));
3363: }
3364: }
3365: }
3366: PetscCall(DMLabelDestroy(&subpointMap));
3367: PetscCall(DMSetUp(subdm));
3368: /* Set cones */
3369: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
3370: PetscCall(PetscMalloc2(maxConeSize, &coneNew, maxConeSize, &orntNew));
3371: for (d = 0; d <= sdim; ++d) {
3372: for (p = 0; p < numSubPoints[d]; ++p) {
3373: const PetscInt point = subpoints[d][p];
3374: const PetscInt subpoint = firstSubPoint[d] + p;
3375: const PetscInt *cone, *ornt;
3376: PetscInt coneSize, subconeSize, coneSizeNew, c, subc, fornt = 0;
3378: if (d == sdim - 1) {
3379: const PetscInt *support, *cone, *ornt;
3380: PetscInt supportSize, coneSize, s, subc;
3382: PetscCall(DMPlexGetSupport(dm, point, &support));
3383: PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
3384: for (s = 0; s < supportSize; ++s) {
3385: PetscBool isHybrid = PETSC_FALSE;
3387: PetscCall(DMPlexCellIsHybrid_Internal(dm, support[s], &isHybrid));
3388: if (!isHybrid) continue;
3389: PetscCall(PetscFindInt(support[s], numSubPoints[d + 1], subpoints[d + 1], &subc));
3390: if (subc >= 0) {
3391: const PetscInt ccell = subpoints[d + 1][subc];
3393: PetscCall(DMPlexGetCone(dm, ccell, &cone));
3394: PetscCall(DMPlexGetConeSize(dm, ccell, &coneSize));
3395: PetscCall(DMPlexGetConeOrientation(dm, ccell, &ornt));
3396: for (c = 0; c < coneSize; ++c) {
3397: if (cone[c] == point) {
3398: fornt = ornt[c];
3399: break;
3400: }
3401: }
3402: break;
3403: }
3404: }
3405: }
3406: PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
3407: PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize));
3408: PetscCall(DMPlexGetCone(dm, point, &cone));
3409: PetscCall(DMPlexGetConeOrientation(dm, point, &ornt));
3410: for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
3411: PetscCall(PetscFindInt(cone[c], numSubPoints[d - 1], subpoints[d - 1], &subc));
3412: if (subc >= 0) {
3413: coneNew[coneSizeNew] = firstSubPoint[d - 1] + subc;
3414: orntNew[coneSizeNew] = ornt[c];
3415: ++coneSizeNew;
3416: }
3417: }
3418: PetscCheck(coneSizeNew == subconeSize, comm, PETSC_ERR_PLIB, "Number of cone points located %" PetscInt_FMT " does not match subcone size %" PetscInt_FMT, coneSizeNew, subconeSize);
3419: PetscCall(DMPlexSetCone(subdm, subpoint, coneNew));
3420: PetscCall(DMPlexSetConeOrientation(subdm, subpoint, orntNew));
3421: if (fornt < 0) PetscCall(DMPlexOrientPoint(subdm, subpoint, fornt));
3422: }
3423: }
3424: PetscCall(PetscFree2(coneNew, orntNew));
3425: PetscCall(DMPlexSymmetrize(subdm));
3426: PetscCall(DMPlexStratify(subdm));
3427: /* Build coordinates */
3428: {
3429: PetscSection coordSection, subCoordSection;
3430: Vec coordinates, subCoordinates;
3431: PetscScalar *coords, *subCoords;
3432: PetscInt cdim, numComp, coordSize;
3433: const char *name;
3435: PetscCall(DMGetCoordinateDim(dm, &cdim));
3436: PetscCall(DMGetCoordinateSection(dm, &coordSection));
3437: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3438: PetscCall(DMGetCoordinateSection(subdm, &subCoordSection));
3439: PetscCall(PetscSectionSetNumFields(subCoordSection, 1));
3440: PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp));
3441: PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp));
3442: PetscCall(PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0] + numSubPoints[0]));
3443: for (v = 0; v < numSubPoints[0]; ++v) {
3444: const PetscInt vertex = subpoints[0][v];
3445: const PetscInt subvertex = firstSubPoint[0] + v;
3446: PetscInt dof;
3448: PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3449: PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof));
3450: PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof));
3451: }
3452: PetscCall(PetscSectionSetUp(subCoordSection));
3453: PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize));
3454: PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates));
3455: PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
3456: PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name));
3457: PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE));
3458: PetscCall(VecSetBlockSize(subCoordinates, cdim));
3459: PetscCall(VecSetType(subCoordinates, VECSTANDARD));
3460: PetscCall(VecGetArray(coordinates, &coords));
3461: PetscCall(VecGetArray(subCoordinates, &subCoords));
3462: for (v = 0; v < numSubPoints[0]; ++v) {
3463: const PetscInt vertex = subpoints[0][v];
3464: const PetscInt subvertex = firstSubPoint[0] + v;
3465: PetscInt dof, off, sdof, soff, d;
3467: PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3468: PetscCall(PetscSectionGetOffset(coordSection, vertex, &off));
3469: PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof));
3470: PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff));
3471: PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof);
3472: for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d];
3473: }
3474: PetscCall(VecRestoreArray(coordinates, &coords));
3475: PetscCall(VecRestoreArray(subCoordinates, &subCoords));
3476: PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates));
3477: PetscCall(VecDestroy(&subCoordinates));
3478: }
3479: /* Build SF: We need this complexity because subpoints might not be selected on the owning process */
3480: {
3481: PetscSF sfPoint, sfPointSub;
3482: IS subpIS;
3483: const PetscSFNode *remotePoints;
3484: PetscSFNode *sremotePoints = NULL, *newLocalPoints = NULL, *newOwners = NULL;
3485: const PetscInt *localPoints, *subpoints, *rootdegree;
3486: PetscInt *slocalPoints = NULL, *sortedPoints = NULL, *sortedIndices = NULL;
3487: PetscInt numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl = 0, ll = 0, pStart, pEnd, p;
3488: PetscMPIInt rank, size;
3490: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3491: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
3492: PetscCall(DMGetPointSF(dm, &sfPoint));
3493: PetscCall(DMGetPointSF(subdm, &sfPointSub));
3494: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3495: PetscCall(DMPlexGetChart(subdm, NULL, &numSubroots));
3496: PetscCall(DMPlexGetSubpointIS(subdm, &subpIS));
3497: if (subpIS) {
3498: PetscBool sorted = PETSC_TRUE;
3500: PetscCall(ISGetIndices(subpIS, &subpoints));
3501: PetscCall(ISGetLocalSize(subpIS, &numSubpoints));
3502: for (p = 1; p < numSubpoints; ++p) sorted = sorted && (subpoints[p] >= subpoints[p - 1]) ? PETSC_TRUE : PETSC_FALSE;
3503: if (!sorted) {
3504: PetscCall(PetscMalloc2(numSubpoints, &sortedPoints, numSubpoints, &sortedIndices));
3505: for (p = 0; p < numSubpoints; ++p) sortedIndices[p] = p;
3506: PetscCall(PetscArraycpy(sortedPoints, subpoints, numSubpoints));
3507: PetscCall(PetscSortIntWithArray(numSubpoints, sortedPoints, sortedIndices));
3508: }
3509: }
3510: PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints));
3511: if (numRoots >= 0) {
3512: PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree));
3513: PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree));
3514: PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners));
3515: for (p = 0; p < pEnd - pStart; ++p) {
3516: newLocalPoints[p].rank = -2;
3517: newLocalPoints[p].index = -2;
3518: }
3519: /* Set subleaves */
3520: for (l = 0; l < numLeaves; ++l) {
3521: const PetscInt point = localPoints[l];
3522: const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices);
3524: if (subpoint < 0) continue;
3525: newLocalPoints[point - pStart].rank = rank;
3526: newLocalPoints[point - pStart].index = subpoint;
3527: ++numSubleaves;
3528: }
3529: /* Must put in owned subpoints */
3530: for (p = pStart; p < pEnd; ++p) {
3531: newOwners[p - pStart].rank = -3;
3532: newOwners[p - pStart].index = -3;
3533: }
3534: for (p = 0; p < numSubpoints; ++p) {
3535: /* Hold on to currently owned points */
3536: if (rootdegree[subpoints[p] - pStart]) newOwners[subpoints[p] - pStart].rank = rank + size;
3537: else newOwners[subpoints[p] - pStart].rank = rank;
3538: newOwners[subpoints[p] - pStart].index = p;
3539: }
3540: PetscCall(PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3541: PetscCall(PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3542: for (p = pStart; p < pEnd; ++p)
3543: if (newOwners[p - pStart].rank >= size) newOwners[p - pStart].rank -= size;
3544: PetscCall(PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3545: PetscCall(PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3546: PetscCall(PetscMalloc1(numSubleaves, &slocalPoints));
3547: PetscCall(PetscMalloc1(numSubleaves, &sremotePoints));
3548: for (l = 0; l < numLeaves; ++l) {
3549: const PetscInt point = localPoints[l];
3550: const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices);
3552: if (subpoint < 0) continue;
3553: if (newLocalPoints[point].rank == rank) {
3554: ++ll;
3555: continue;
3556: }
3557: slocalPoints[sl] = subpoint;
3558: sremotePoints[sl].rank = newLocalPoints[point].rank;
3559: sremotePoints[sl].index = newLocalPoints[point].index;
3560: PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point);
3561: PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point);
3562: ++sl;
3563: }
3564: PetscCheck(sl + ll == numSubleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubleaves);
3565: PetscCall(PetscFree2(newLocalPoints, newOwners));
3566: PetscCall(PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER));
3567: }
3568: if (subpIS) PetscCall(ISRestoreIndices(subpIS, &subpoints));
3569: PetscCall(PetscFree2(sortedPoints, sortedIndices));
3570: }
3571: /* Filter labels */
3572: PetscCall(DMPlexFilterLabels_Internal(dm, numSubPoints, subpoints, firstSubPoint, subdm));
3573: /* Cleanup */
3574: for (d = 0; d <= sdim; ++d) {
3575: if (subpointIS[d]) PetscCall(ISRestoreIndices(subpointIS[d], &subpoints[d]));
3576: PetscCall(ISDestroy(&subpointIS[d]));
3577: }
3578: PetscCall(PetscFree4(numSubPoints, firstSubPoint, subpointIS, subpoints));
3579: PetscFunctionReturn(PETSC_SUCCESS);
3580: }
3582: static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM subdm)
3583: {
3584: PetscFunctionBegin;
3585: PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, vertexLabel, value, markedFaces, PETSC_FALSE, 1, subdm));
3586: PetscFunctionReturn(PETSC_SUCCESS);
3587: }
3589: /*@
3590: DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label
3592: Input Parameters:
3593: + dm - The original mesh
3594: . vertexLabel - The DMLabel marking points contained in the surface
3595: . value - The label value to use
3596: - markedFaces - PETSC_TRUE if surface faces are marked in addition to vertices, PETSC_FALSE if only vertices are marked
3598: Output Parameter:
3599: . subdm - The surface mesh
3601: Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().
3603: Level: developer
3605: .seealso: `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()`
3606: @*/
3607: PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM *subdm)
3608: {
3609: DMPlexInterpolatedFlag interpolated;
3610: PetscInt dim, cdim;
3612: PetscFunctionBegin;
3615: PetscCall(DMGetDimension(dm, &dim));
3616: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm));
3617: PetscCall(DMSetType(*subdm, DMPLEX));
3618: PetscCall(DMSetDimension(*subdm, dim - 1));
3619: PetscCall(DMGetCoordinateDim(dm, &cdim));
3620: PetscCall(DMSetCoordinateDim(*subdm, cdim));
3621: PetscCall(DMPlexIsInterpolated(dm, &interpolated));
3622: PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes");
3623: if (interpolated) {
3624: PetscCall(DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, markedFaces, *subdm));
3625: } else {
3626: PetscCall(DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm));
3627: }
3628: PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm));
3629: PetscFunctionReturn(PETSC_SUCCESS);
3630: }
3632: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm)
3633: {
3634: MPI_Comm comm;
3635: DMLabel subpointMap;
3636: IS subvertexIS;
3637: const PetscInt *subVertices;
3638: PetscInt numSubVertices, firstSubVertex, numSubCells, *subCells = NULL;
3639: PetscInt *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV;
3640: PetscInt c, f;
3642: PetscFunctionBegin;
3643: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3644: /* Create subpointMap which marks the submesh */
3645: PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap));
3646: PetscCall(DMPlexSetSubpointMap(subdm, subpointMap));
3647: PetscCall(DMLabelDestroy(&subpointMap));
3648: PetscCall(DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm));
3649: /* Setup chart */
3650: PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices));
3651: PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells));
3652: PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices));
3653: PetscCall(DMPlexSetVTKCellHeight(subdm, 1));
3654: /* Set cone sizes */
3655: firstSubVertex = numSubCells;
3656: firstSubFace = numSubCells + numSubVertices;
3657: newFacePoint = firstSubFace;
3658: PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS));
3659: if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices));
3660: for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1));
3661: for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV));
3662: PetscCall(DMSetUp(subdm));
3663: /* Create face cones */
3664: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
3665: PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3666: for (c = 0; c < numSubCells; ++c) {
3667: const PetscInt cell = subCells[c];
3668: const PetscInt subcell = c;
3669: const PetscInt *cone, *cells;
3670: PetscBool isHybrid = PETSC_FALSE;
3671: PetscInt numCells, subVertex, p, v;
3673: PetscCall(DMPlexCellIsHybrid_Internal(dm, cell, &isHybrid));
3674: if (!isHybrid) continue;
3675: PetscCall(DMPlexGetCone(dm, cell, &cone));
3676: for (v = 0; v < nFV; ++v) {
3677: PetscCall(PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex));
3678: subface[v] = firstSubVertex + subVertex;
3679: }
3680: PetscCall(DMPlexSetCone(subdm, newFacePoint, subface));
3681: PetscCall(DMPlexSetCone(subdm, subcell, &newFacePoint));
3682: PetscCall(DMPlexGetJoin(dm, nFV, cone, &numCells, &cells));
3683: /* Not true in parallel
3684: PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
3685: for (p = 0; p < numCells; ++p) {
3686: PetscInt negsubcell;
3687: PetscBool isHybrid = PETSC_FALSE;
3689: PetscCall(DMPlexCellIsHybrid_Internal(dm, cells[p], &isHybrid));
3690: if (isHybrid) continue;
3691: /* I know this is a crap search */
3692: for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) {
3693: if (subCells[negsubcell] == cells[p]) break;
3694: }
3695: PetscCheck(negsubcell != numSubCells, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %" PetscInt_FMT, cell);
3696: PetscCall(DMPlexSetCone(subdm, negsubcell, &newFacePoint));
3697: }
3698: PetscCall(DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells));
3699: ++newFacePoint;
3700: }
3701: PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3702: PetscCall(DMPlexSymmetrize(subdm));
3703: PetscCall(DMPlexStratify(subdm));
3704: /* Build coordinates */
3705: {
3706: PetscSection coordSection, subCoordSection;
3707: Vec coordinates, subCoordinates;
3708: PetscScalar *coords, *subCoords;
3709: PetscInt cdim, numComp, coordSize, v;
3710: const char *name;
3712: PetscCall(DMGetCoordinateDim(dm, &cdim));
3713: PetscCall(DMGetCoordinateSection(dm, &coordSection));
3714: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3715: PetscCall(DMGetCoordinateSection(subdm, &subCoordSection));
3716: PetscCall(PetscSectionSetNumFields(subCoordSection, 1));
3717: PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp));
3718: PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp));
3719: PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices));
3720: for (v = 0; v < numSubVertices; ++v) {
3721: const PetscInt vertex = subVertices[v];
3722: const PetscInt subvertex = firstSubVertex + v;
3723: PetscInt dof;
3725: PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3726: PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof));
3727: PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof));
3728: }
3729: PetscCall(PetscSectionSetUp(subCoordSection));
3730: PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize));
3731: PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates));
3732: PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
3733: PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name));
3734: PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE));
3735: PetscCall(VecSetBlockSize(subCoordinates, cdim));
3736: PetscCall(VecSetType(subCoordinates, VECSTANDARD));
3737: PetscCall(VecGetArray(coordinates, &coords));
3738: PetscCall(VecGetArray(subCoordinates, &subCoords));
3739: for (v = 0; v < numSubVertices; ++v) {
3740: const PetscInt vertex = subVertices[v];
3741: const PetscInt subvertex = firstSubVertex + v;
3742: PetscInt dof, off, sdof, soff, d;
3744: PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3745: PetscCall(PetscSectionGetOffset(coordSection, vertex, &off));
3746: PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof));
3747: PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff));
3748: PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof);
3749: for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d];
3750: }
3751: PetscCall(VecRestoreArray(coordinates, &coords));
3752: PetscCall(VecRestoreArray(subCoordinates, &subCoords));
3753: PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates));
3754: PetscCall(VecDestroy(&subCoordinates));
3755: }
3756: /* Build SF */
3757: CHKMEMQ;
3758: {
3759: PetscSF sfPoint, sfPointSub;
3760: const PetscSFNode *remotePoints;
3761: PetscSFNode *sremotePoints, *newLocalPoints, *newOwners;
3762: const PetscInt *localPoints;
3763: PetscInt *slocalPoints;
3764: PetscInt numRoots, numLeaves, numSubRoots = numSubCells + numSubFaces + numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd;
3765: PetscMPIInt rank;
3767: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3768: PetscCall(DMGetPointSF(dm, &sfPoint));
3769: PetscCall(DMGetPointSF(subdm, &sfPointSub));
3770: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3771: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3772: PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints));
3773: if (numRoots >= 0) {
3774: /* Only vertices should be shared */
3775: PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners));
3776: for (p = 0; p < pEnd - pStart; ++p) {
3777: newLocalPoints[p].rank = -2;
3778: newLocalPoints[p].index = -2;
3779: }
3780: /* Set subleaves */
3781: for (l = 0; l < numLeaves; ++l) {
3782: const PetscInt point = localPoints[l];
3783: const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);
3785: PetscCheck(!(point < vStart) || !(point >= vEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %" PetscInt_FMT, point);
3786: if (subPoint < 0) continue;
3787: newLocalPoints[point - pStart].rank = rank;
3788: newLocalPoints[point - pStart].index = subPoint;
3789: ++numSubLeaves;
3790: }
3791: /* Must put in owned subpoints */
3792: for (p = pStart; p < pEnd; ++p) {
3793: const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices);
3795: if (subPoint < 0) {
3796: newOwners[p - pStart].rank = -3;
3797: newOwners[p - pStart].index = -3;
3798: } else {
3799: newOwners[p - pStart].rank = rank;
3800: newOwners[p - pStart].index = subPoint;
3801: }
3802: }
3803: PetscCall(PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3804: PetscCall(PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3805: PetscCall(PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3806: PetscCall(PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3807: PetscCall(PetscMalloc1(numSubLeaves, &slocalPoints));
3808: PetscCall(PetscMalloc1(numSubLeaves, &sremotePoints));
3809: for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) {
3810: const PetscInt point = localPoints[l];
3811: const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);
3813: if (subPoint < 0) continue;
3814: if (newLocalPoints[point].rank == rank) {
3815: ++ll;
3816: continue;
3817: }
3818: slocalPoints[sl] = subPoint;
3819: sremotePoints[sl].rank = newLocalPoints[point].rank;
3820: sremotePoints[sl].index = newLocalPoints[point].index;
3821: PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point);
3822: PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point);
3823: ++sl;
3824: }
3825: PetscCall(PetscFree2(newLocalPoints, newOwners));
3826: PetscCheck(sl + ll == numSubLeaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubLeaves);
3827: PetscCall(PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER));
3828: }
3829: }
3830: CHKMEMQ;
3831: /* Cleanup */
3832: if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices));
3833: PetscCall(ISDestroy(&subvertexIS));
3834: PetscCall(PetscFree(subCells));
3835: PetscFunctionReturn(PETSC_SUCCESS);
3836: }
3838: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DM subdm)
3839: {
3840: DMLabel label = NULL;
3842: PetscFunctionBegin;
3843: if (labelname) PetscCall(DMGetLabel(dm, labelname, &label));
3844: PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, label, value, PETSC_FALSE, PETSC_TRUE, 1, subdm));
3845: PetscFunctionReturn(PETSC_SUCCESS);
3846: }
3848: /*@C
3849: DMPlexCreateCohesiveSubmesh - Extract from a mesh with cohesive cells the hypersurface defined by one face of the cells. Optionally, a Label can be given to restrict the cells.
3851: Input Parameters:
3852: + dm - The original mesh
3853: . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells
3854: . label - A label name, or NULL
3855: - value - A label value
3857: Output Parameter:
3858: . subdm - The surface mesh
3860: Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().
3862: Level: developer
3864: .seealso: `DMPlexGetSubpointMap()`, `DMPlexCreateSubmesh()`
3865: @*/
3866: PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm)
3867: {
3868: PetscInt dim, cdim, depth;
3870: PetscFunctionBegin;
3873: PetscCall(DMGetDimension(dm, &dim));
3874: PetscCall(DMPlexGetDepth(dm, &depth));
3875: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm));
3876: PetscCall(DMSetType(*subdm, DMPLEX));
3877: PetscCall(DMSetDimension(*subdm, dim - 1));
3878: PetscCall(DMGetCoordinateDim(dm, &cdim));
3879: PetscCall(DMSetCoordinateDim(*subdm, cdim));
3880: if (depth == dim) {
3881: PetscCall(DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm));
3882: } else {
3883: PetscCall(DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm));
3884: }
3885: PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm));
3886: PetscFunctionReturn(PETSC_SUCCESS);
3887: }
3889: /*@
3890: DMPlexFilter - Extract a subset of mesh cells defined by a label as a separate mesh
3892: Input Parameters:
3893: + dm - The original mesh
3894: . cellLabel - The DMLabel marking cells contained in the new mesh
3895: - value - The label value to use
3897: Output Parameter:
3898: . subdm - The new mesh
3900: Notes:
3901: This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`.
3903: Level: developer
3905: .seealso: `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()`, `DMPlexCreateSubmesh()`
3906: @*/
3907: PetscErrorCode DMPlexFilter(DM dm, DMLabel cellLabel, PetscInt value, DM *subdm)
3908: {
3909: PetscInt dim, overlap;
3911: PetscFunctionBegin;
3914: PetscCall(DMGetDimension(dm, &dim));
3915: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm));
3916: PetscCall(DMSetType(*subdm, DMPLEX));
3917: /* Extract submesh in place, could be empty on some procs, could have inconsistency if procs do not both extract a shared cell */
3918: PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, cellLabel, value, PETSC_FALSE, PETSC_FALSE, 0, *subdm));
3919: PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm));
3920: // It is possible to obtain a surface mesh where some faces are in SF
3921: // We should either mark the mesh as having an overlap, or delete these from the SF
3922: PetscCall(DMPlexGetOverlap(dm, &overlap));
3923: if (!overlap) {
3924: PetscSF sf;
3925: const PetscInt *leaves;
3926: PetscInt cStart, cEnd, Nl;
3927: PetscBool hasSubcell = PETSC_FALSE, ghasSubcell;
3929: PetscCall(DMPlexGetHeightStratum(*subdm, 0, &cStart, &cEnd));
3930: PetscCall(DMGetPointSF(*subdm, &sf));
3931: PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
3932: for (PetscInt l = 0; l < Nl; ++l) {
3933: const PetscInt point = leaves ? leaves[l] : l;
3935: if (point >= cStart && point < cEnd) {
3936: hasSubcell = PETSC_TRUE;
3937: break;
3938: }
3939: }
3940: PetscCall(MPIU_Allreduce(&hasSubcell, &ghasSubcell, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
3941: if (ghasSubcell) PetscCall(DMPlexSetOverlap(*subdm, NULL, 1));
3942: }
3943: PetscFunctionReturn(PETSC_SUCCESS);
3944: }
3946: /*@
3947: DMPlexGetSubpointMap - Returns a DMLabel with point dimension as values
3949: Input Parameter:
3950: . dm - The submesh DM
3952: Output Parameter:
3953: . subpointMap - The DMLabel of all the points from the original mesh in this submesh, or NULL if this is not a submesh
3955: Level: developer
3957: .seealso: `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()`
3958: @*/
3959: PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap)
3960: {
3961: PetscFunctionBegin;
3964: *subpointMap = ((DM_Plex *)dm->data)->subpointMap;
3965: PetscFunctionReturn(PETSC_SUCCESS);
3966: }
3968: /*@
3969: DMPlexSetSubpointMap - Sets the DMLabel with point dimension as values
3971: Input Parameters:
3972: + dm - The submesh DM
3973: - subpointMap - The DMLabel of all the points from the original mesh in this submesh
3975: Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh()
3977: Level: developer
3979: .seealso: `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()`
3980: @*/
3981: PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap)
3982: {
3983: DM_Plex *mesh = (DM_Plex *)dm->data;
3984: DMLabel tmp;
3986: PetscFunctionBegin;
3988: tmp = mesh->subpointMap;
3989: mesh->subpointMap = subpointMap;
3990: PetscCall(PetscObjectReference((PetscObject)mesh->subpointMap));
3991: PetscCall(DMLabelDestroy(&tmp));
3992: PetscFunctionReturn(PETSC_SUCCESS);
3993: }
3995: static PetscErrorCode DMPlexCreateSubpointIS_Internal(DM dm, IS *subpointIS)
3996: {
3997: DMLabel spmap;
3998: PetscInt depth, d;
4000: PetscFunctionBegin;
4001: PetscCall(DMPlexGetSubpointMap(dm, &spmap));
4002: PetscCall(DMPlexGetDepth(dm, &depth));
4003: if (spmap && depth >= 0) {
4004: DM_Plex *mesh = (DM_Plex *)dm->data;
4005: PetscInt *points, *depths;
4006: PetscInt pStart, pEnd, p, off;
4008: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4009: PetscCheck(!pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %" PetscInt_FMT, pStart);
4010: PetscCall(PetscMalloc1(pEnd, &points));
4011: PetscCall(DMGetWorkArray(dm, depth + 1, MPIU_INT, &depths));
4012: depths[0] = depth;
4013: depths[1] = 0;
4014: for (d = 2; d <= depth; ++d) depths[d] = depth + 1 - d;
4015: for (d = 0, off = 0; d <= depth; ++d) {
4016: const PetscInt dep = depths[d];
4017: PetscInt depStart, depEnd, n;
4019: PetscCall(DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd));
4020: PetscCall(DMLabelGetStratumSize(spmap, dep, &n));
4021: if (((d < 2) && (depth > 1)) || (d == 1)) { /* Only check vertices and cells for now since the map is broken for others */
4022: PetscCheck(n == depEnd - depStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " at depth %" PetscInt_FMT " should be %" PetscInt_FMT, n, dep, depEnd - depStart);
4023: } else {
4024: if (!n) {
4025: if (d == 0) {
4026: /* Missing cells */
4027: for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = -1;
4028: } else {
4029: /* Missing faces */
4030: for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = PETSC_MAX_INT;
4031: }
4032: }
4033: }
4034: if (n) {
4035: IS is;
4036: const PetscInt *opoints;
4038: PetscCall(DMLabelGetStratumIS(spmap, dep, &is));
4039: PetscCall(ISGetIndices(is, &opoints));
4040: for (p = 0; p < n; ++p, ++off) points[off] = opoints[p];
4041: PetscCall(ISRestoreIndices(is, &opoints));
4042: PetscCall(ISDestroy(&is));
4043: }
4044: }
4045: PetscCall(DMRestoreWorkArray(dm, depth + 1, MPIU_INT, &depths));
4046: PetscCheck(off == pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " should be %" PetscInt_FMT, off, pEnd);
4047: PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS));
4048: PetscCall(PetscObjectStateGet((PetscObject)spmap, &mesh->subpointState));
4049: }
4050: PetscFunctionReturn(PETSC_SUCCESS);
4051: }
4053: /*@
4054: DMPlexGetSubpointIS - Returns an IS covering the entire subdm chart with the original points as data
4056: Input Parameter:
4057: . dm - The submesh DM
4059: Output Parameter:
4060: . subpointIS - The IS of all the points from the original mesh in this submesh, or NULL if this is not a submesh
4062: Note: This IS is guaranteed to be sorted by the construction of the submesh
4064: Level: developer
4066: .seealso: `DMPlexCreateSubmesh()`, `DMPlexGetSubpointMap()`
4067: @*/
4068: PetscErrorCode DMPlexGetSubpointIS(DM dm, IS *subpointIS)
4069: {
4070: DM_Plex *mesh = (DM_Plex *)dm->data;
4071: DMLabel spmap;
4072: PetscObjectState state;
4074: PetscFunctionBegin;
4077: PetscCall(DMPlexGetSubpointMap(dm, &spmap));
4078: PetscCall(PetscObjectStateGet((PetscObject)spmap, &state));
4079: if (state != mesh->subpointState || !mesh->subpointIS) PetscCall(DMPlexCreateSubpointIS_Internal(dm, &mesh->subpointIS));
4080: *subpointIS = mesh->subpointIS;
4081: PetscFunctionReturn(PETSC_SUCCESS);
4082: }
4084: /*@
4085: DMGetEnclosureRelation - Get the relationship between dmA and dmB
4087: Input Parameters:
4088: + dmA - The first DM
4089: - dmB - The second DM
4091: Output Parameter:
4092: . rel - The relation of dmA to dmB
4094: Level: intermediate
4096: .seealso: `DMGetEnclosurePoint()`
4097: @*/
4098: PetscErrorCode DMGetEnclosureRelation(DM dmA, DM dmB, DMEnclosureType *rel)
4099: {
4100: DM plexA, plexB, sdm;
4101: DMLabel spmap;
4102: PetscInt pStartA, pEndA, pStartB, pEndB, NpA, NpB;
4104: PetscFunctionBegin;
4106: *rel = DM_ENC_NONE;
4107: if (!dmA || !dmB) PetscFunctionReturn(PETSC_SUCCESS);
4110: if (dmA == dmB) {
4111: *rel = DM_ENC_EQUALITY;
4112: PetscFunctionReturn(PETSC_SUCCESS);
4113: }
4114: PetscCall(DMConvert(dmA, DMPLEX, &plexA));
4115: PetscCall(DMConvert(dmB, DMPLEX, &plexB));
4116: PetscCall(DMPlexGetChart(plexA, &pStartA, &pEndA));
4117: PetscCall(DMPlexGetChart(plexB, &pStartB, &pEndB));
4118: /* Assumption 1: subDMs have smaller charts than the DMs that they originate from
4119: - The degenerate case of a subdomain which includes all of the domain on some process can be treated as equality */
4120: if ((pStartA == pStartB) && (pEndA == pEndB)) {
4121: *rel = DM_ENC_EQUALITY;
4122: goto end;
4123: }
4124: NpA = pEndA - pStartA;
4125: NpB = pEndB - pStartB;
4126: if (NpA == NpB) goto end;
4127: sdm = NpA > NpB ? plexB : plexA; /* The other is the original, enclosing dm */
4128: PetscCall(DMPlexGetSubpointMap(sdm, &spmap));
4129: if (!spmap) goto end;
4130: /* TODO Check the space mapped to by subpointMap is same size as dm */
4131: if (NpA > NpB) {
4132: *rel = DM_ENC_SUPERMESH;
4133: } else {
4134: *rel = DM_ENC_SUBMESH;
4135: }
4136: end:
4137: PetscCall(DMDestroy(&plexA));
4138: PetscCall(DMDestroy(&plexB));
4139: PetscFunctionReturn(PETSC_SUCCESS);
4140: }
4142: /*@
4143: DMGetEnclosurePoint - Get the point pA in dmA which corresponds to the point pB in dmB
4145: Input Parameters:
4146: + dmA - The first DM
4147: . dmB - The second DM
4148: . etype - The type of enclosure relation that dmA has to dmB
4149: - pB - A point of dmB
4151: Output Parameter:
4152: . pA - The corresponding point of dmA
4154: Level: intermediate
4156: .seealso: `DMGetEnclosureRelation()`
4157: @*/
4158: PetscErrorCode DMGetEnclosurePoint(DM dmA, DM dmB, DMEnclosureType etype, PetscInt pB, PetscInt *pA)
4159: {
4160: DM sdm;
4161: IS subpointIS;
4162: const PetscInt *subpoints;
4163: PetscInt numSubpoints;
4165: PetscFunctionBegin;
4166: /* TODO Cache the IS, making it look like an index */
4167: switch (etype) {
4168: case DM_ENC_SUPERMESH:
4169: sdm = dmB;
4170: PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS));
4171: PetscCall(ISGetIndices(subpointIS, &subpoints));
4172: *pA = subpoints[pB];
4173: PetscCall(ISRestoreIndices(subpointIS, &subpoints));
4174: break;
4175: case DM_ENC_SUBMESH:
4176: sdm = dmA;
4177: PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS));
4178: PetscCall(ISGetLocalSize(subpointIS, &numSubpoints));
4179: PetscCall(ISGetIndices(subpointIS, &subpoints));
4180: PetscCall(PetscFindInt(pB, numSubpoints, subpoints, pA));
4181: if (*pA < 0) {
4182: PetscCall(DMViewFromOptions(dmA, NULL, "-dm_enc_A_view"));
4183: PetscCall(DMViewFromOptions(dmB, NULL, "-dm_enc_B_view"));
4184: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " not found in submesh", pB);
4185: }
4186: PetscCall(ISRestoreIndices(subpointIS, &subpoints));
4187: break;
4188: case DM_ENC_EQUALITY:
4189: case DM_ENC_NONE:
4190: *pA = pB;
4191: break;
4192: case DM_ENC_UNKNOWN: {
4193: DMEnclosureType enc;
4195: PetscCall(DMGetEnclosureRelation(dmA, dmB, &enc));
4196: PetscCall(DMGetEnclosurePoint(dmA, dmB, enc, pB, pA));
4197: } break;
4198: default:
4199: SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Invalid enclosure type %d", (int)etype);
4200: }
4201: PetscFunctionReturn(PETSC_SUCCESS);
4202: }