Actual source code: plexsubmesh.c
petsc-3.7.7 2017-09-25
1: #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/
2: #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/
3: #include <petscsf.h>
7: PetscErrorCode DMPlexMarkBoundaryFaces_Internal(DM dm, PetscInt cellHeight, DMLabel label)
8: {
9: PetscInt fStart, fEnd, f;
14: DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);
15: for (f = fStart; f < fEnd; ++f) {
16: PetscInt supportSize;
18: DMPlexGetSupportSize(dm, f, &supportSize);
19: if (supportSize == 1) {DMLabelSetValue(label, f, 1);}
20: }
21: return(0);
22: }
26: /*@
27: DMPlexMarkBoundaryFaces - Mark all faces on the boundary
29: Not Collective
31: Input Parameter:
32: . dm - The original DM
34: Output Parameter:
35: . label - The DMLabel marking boundary faces with value 1
37: Level: developer
39: .seealso: DMLabelCreate(), DMCreateLabel()
40: @*/
41: PetscErrorCode DMPlexMarkBoundaryFaces(DM dm, DMLabel label)
42: {
46: DMPlexMarkBoundaryFaces_Internal(dm, 0, label);
47: return(0);
48: }
52: PetscErrorCode DMPlexLabelComplete_Internal(DM dm, DMLabel label, PetscBool completeCells)
53: {
54: IS valueIS;
55: const PetscInt *values;
56: PetscInt numValues, v, cStart, cEnd;
57: PetscErrorCode ierr;
60: DMLabelGetNumValues(label, &numValues);
61: DMLabelGetValueIS(label, &valueIS);
62: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
63: ISGetIndices(valueIS, &values);
64: for (v = 0; v < numValues; ++v) {
65: IS pointIS;
66: const PetscInt *points;
67: PetscInt numPoints, p;
69: DMLabelGetStratumSize(label, values[v], &numPoints);
70: DMLabelGetStratumIS(label, values[v], &pointIS);
71: ISGetIndices(pointIS, &points);
72: for (p = 0; p < numPoints; ++p) {
73: PetscInt q = points[p];
74: PetscInt *closure = NULL;
75: PetscInt closureSize, c;
77: if (cStart <= q && q < cEnd && !completeCells) { /* skip cells */
78: continue;
79: }
80: DMPlexGetTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure);
81: for (c = 0; c < closureSize*2; c += 2) {
82: DMLabelSetValue(label, closure[c], values[v]);
83: }
84: DMPlexRestoreTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure);
85: }
86: ISRestoreIndices(pointIS, &points);
87: ISDestroy(&pointIS);
88: }
89: ISRestoreIndices(valueIS, &values);
90: ISDestroy(&valueIS);
91: return(0);
92: }
96: /*@
97: DMPlexLabelComplete - Starting with a label marking points on a surface, we add the transitive closure to the surface
99: Input Parameters:
100: + dm - The DM
101: - label - A DMLabel marking the surface points
103: Output Parameter:
104: . label - A DMLabel marking all surface points in the transitive closure
106: Level: developer
108: .seealso: DMPlexLabelCohesiveComplete()
109: @*/
110: PetscErrorCode DMPlexLabelComplete(DM dm, DMLabel label)
111: {
115: DMPlexLabelComplete_Internal(dm, label, PETSC_TRUE);
116: return(0);
117: }
121: /*@
122: DMPlexLabelAddCells - Starting with a label marking faces on a surface, we add a cell for each face
124: Input Parameters:
125: + dm - The DM
126: - label - A DMLabel marking the surface points
128: Output Parameter:
129: . label - A DMLabel incorporating cells
131: Level: developer
133: Note: The cells allow FEM boundary conditions to be applied using the cell geometry
135: .seealso: DMPlexLabelComplete(), DMPlexLabelCohesiveComplete()
136: @*/
137: PetscErrorCode DMPlexLabelAddCells(DM dm, DMLabel label)
138: {
139: IS valueIS;
140: const PetscInt *values;
141: PetscInt numValues, v, cStart, cEnd, cEndInterior;
142: PetscErrorCode ierr;
145: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
146: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
147: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
148: DMLabelGetNumValues(label, &numValues);
149: DMLabelGetValueIS(label, &valueIS);
150: ISGetIndices(valueIS, &values);
151: for (v = 0; v < numValues; ++v) {
152: IS pointIS;
153: const PetscInt *points;
154: PetscInt numPoints, p;
156: DMLabelGetStratumSize(label, values[v], &numPoints);
157: DMLabelGetStratumIS(label, values[v], &pointIS);
158: ISGetIndices(pointIS, &points);
159: for (p = 0; p < numPoints; ++p) {
160: PetscInt *closure = NULL;
161: PetscInt closureSize, point, cl;
163: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure);
164: for (cl = closureSize-1; cl > 0; --cl) {
165: point = closure[cl*2];
166: if ((point >= cStart) && (point < cEnd)) {DMLabelSetValue(label, point, values[v]); break;}
167: }
168: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure);
169: }
170: ISRestoreIndices(pointIS, &points);
171: ISDestroy(&pointIS);
172: }
173: ISRestoreIndices(valueIS, &values);
174: ISDestroy(&valueIS);
175: return(0);
176: }
180: /*@
181: DMPlexLabelClearCells - Remove cells from a label
183: Input Parameters:
184: + dm - The DM
185: - label - A DMLabel marking surface points and their adjacent cells
187: Output Parameter:
188: . label - A DMLabel without cells
190: Level: developer
192: Note: This undoes DMPlexLabelAddCells()
194: .seealso: DMPlexLabelComplete(), DMPlexLabelCohesiveComplete(), DMPlexLabelAddCells()
195: @*/
196: PetscErrorCode DMPlexLabelClearCells(DM dm, DMLabel label)
197: {
198: IS valueIS;
199: const PetscInt *values;
200: PetscInt numValues, v, cStart, cEnd, cEndInterior;
201: PetscErrorCode ierr;
204: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
205: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
206: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
207: DMLabelGetNumValues(label, &numValues);
208: DMLabelGetValueIS(label, &valueIS);
209: ISGetIndices(valueIS, &values);
210: for (v = 0; v < numValues; ++v) {
211: IS pointIS;
212: const PetscInt *points;
213: PetscInt numPoints, p;
215: DMLabelGetStratumSize(label, values[v], &numPoints);
216: DMLabelGetStratumIS(label, values[v], &pointIS);
217: ISGetIndices(pointIS, &points);
218: for (p = 0; p < numPoints; ++p) {
219: PetscInt point = points[p];
221: if (point >= cStart && point < cEnd) {
222: DMLabelClearValue(label,point,values[v]);
223: }
224: }
225: ISRestoreIndices(pointIS, &points);
226: ISDestroy(&pointIS);
227: }
228: ISRestoreIndices(valueIS, &values);
229: ISDestroy(&valueIS);
230: return(0);
231: }
235: /* take (oldEnd, added) pairs, ordered by height and convert them to (oldstart, newstart) pairs, ordered by ascending
236: * index (skipping first, which is (0,0)) */
237: PETSC_STATIC_INLINE PetscErrorCode DMPlexShiftPointSetUp_Internal(PetscInt depth, PetscInt depthShift[])
238: {
239: PetscInt d, off = 0;
242: /* sort by (oldend): yes this is an O(n^2) sort, we expect depth <= 3 */
243: for (d = 0; d < depth; d++) {
244: PetscInt firstd = d;
245: PetscInt firstStart = depthShift[2*d];
246: PetscInt e;
248: for (e = d+1; e <= depth; e++) {
249: if (depthShift[2*e] < firstStart) {
250: firstd = e;
251: firstStart = depthShift[2*d];
252: }
253: }
254: if (firstd != d) {
255: PetscInt swap[2];
257: e = firstd;
258: swap[0] = depthShift[2*d];
259: swap[1] = depthShift[2*d+1];
260: depthShift[2*d] = depthShift[2*e];
261: depthShift[2*d+1] = depthShift[2*e+1];
262: depthShift[2*e] = swap[0];
263: depthShift[2*e+1] = swap[1];
264: }
265: }
266: /* convert (oldstart, added) to (oldstart, newstart) */
267: for (d = 0; d <= depth; d++) {
268: off += depthShift[2*d+1];
269: depthShift[2*d+1] = depthShift[2*d] + off;
270: }
271: return(0);
272: }
276: /* depthShift is a list of (old, new) pairs */
277: PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[])
278: {
279: PetscInt d;
280: PetscInt newOff = 0;
282: for (d = 0; d <= depth; d++) {
283: if (p < depthShift[2*d]) return p + newOff;
284: else newOff = depthShift[2*d+1] - depthShift[2*d];
285: }
286: return p + newOff;
287: }
291: /* depthShift is a list of (old, new) pairs */
292: PETSC_STATIC_INLINE PetscInt DMPlexShiftPointInverse_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[])
293: {
294: PetscInt d;
295: PetscInt newOff = 0;
297: for (d = 0; d <= depth; d++) {
298: if (p < depthShift[2*d+1]) return p + newOff;
299: else newOff = depthShift[2*d] - depthShift[2*d+1];
300: }
301: return p + newOff;
302: }
306: static PetscErrorCode DMPlexShiftSizes_Internal(DM dm, PetscInt depthShift[], DM dmNew)
307: {
308: PetscInt depth = 0, d, pStart, pEnd, p;
312: DMPlexGetDepth(dm, &depth);
313: if (depth < 0) return(0);
314: /* Step 1: Expand chart */
315: DMPlexGetChart(dm, &pStart, &pEnd);
316: pEnd = DMPlexShiftPoint_Internal(pEnd,depth,depthShift);
317: DMPlexSetChart(dmNew, pStart, pEnd);
318: /* Step 2: Set cone and support sizes */
319: for (d = 0; d <= depth; ++d) {
320: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
321: for (p = pStart; p < pEnd; ++p) {
322: PetscInt newp = DMPlexShiftPoint_Internal(p, depth, depthShift);
323: PetscInt size;
325: DMPlexGetConeSize(dm, p, &size);
326: DMPlexSetConeSize(dmNew, newp, size);
327: DMPlexGetSupportSize(dm, p, &size);
328: DMPlexSetSupportSize(dmNew, newp, size);
329: }
330: }
331: return(0);
332: }
336: static PetscErrorCode DMPlexShiftPoints_Internal(DM dm, PetscInt depthShift[], DM dmNew)
337: {
338: PetscInt *newpoints;
339: PetscInt depth = 0, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, pStart, pEnd, p;
343: DMPlexGetDepth(dm, &depth);
344: if (depth < 0) return(0);
345: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
346: DMPlexGetMaxSizes(dmNew, &maxConeSizeNew, &maxSupportSizeNew);
347: PetscMalloc1(PetscMax(PetscMax(maxConeSize, maxSupportSize), PetscMax(maxConeSizeNew, maxSupportSizeNew)),&newpoints);
348: /* Step 5: Set cones and supports */
349: DMPlexGetChart(dm, &pStart, &pEnd);
350: for (p = pStart; p < pEnd; ++p) {
351: const PetscInt *points = NULL, *orientations = NULL;
352: PetscInt size,sizeNew, i, newp = DMPlexShiftPoint_Internal(p, depth, depthShift);
354: DMPlexGetConeSize(dm, p, &size);
355: DMPlexGetCone(dm, p, &points);
356: DMPlexGetConeOrientation(dm, p, &orientations);
357: for (i = 0; i < size; ++i) {
358: newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift);
359: }
360: DMPlexSetCone(dmNew, newp, newpoints);
361: DMPlexSetConeOrientation(dmNew, newp, orientations);
362: DMPlexGetSupportSize(dm, p, &size);
363: DMPlexGetSupportSize(dmNew, newp, &sizeNew);
364: DMPlexGetSupport(dm, p, &points);
365: for (i = 0; i < size; ++i) {
366: newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift);
367: }
368: for (i = size; i < sizeNew; ++i) newpoints[i] = 0;
369: DMPlexSetSupport(dmNew, newp, newpoints);
370: }
371: PetscFree(newpoints);
372: return(0);
373: }
377: static PetscErrorCode DMPlexShiftCoordinates_Internal(DM dm, PetscInt depthShift[], DM dmNew)
378: {
379: PetscSection coordSection, newCoordSection;
380: Vec coordinates, newCoordinates;
381: PetscScalar *coords, *newCoords;
382: PetscInt coordSize, sStart, sEnd;
383: PetscInt dim, depth = 0, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v;
384: PetscBool hasCells;
388: DMGetCoordinateDim(dm, &dim);
389: DMPlexGetDepth(dm, &depth);
390: /* Step 8: Convert coordinates */
391: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
392: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
393: DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);
394: DMPlexGetHeightStratum(dmNew, 0, &cStartNew, &cEndNew);
395: DMGetCoordinateSection(dm, &coordSection);
396: PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);
397: PetscSectionSetNumFields(newCoordSection, 1);
398: PetscSectionSetFieldComponents(newCoordSection, 0, dim);
399: PetscSectionGetChart(coordSection, &sStart, &sEnd);
400: hasCells = sStart == cStart ? PETSC_TRUE : PETSC_FALSE;
401: PetscSectionSetChart(newCoordSection, hasCells ? cStartNew : vStartNew, vEndNew);
402: if (hasCells) {
403: for (c = cStart; c < cEnd; ++c) {
404: PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof;
406: PetscSectionGetDof(coordSection, c, &dof);
407: PetscSectionSetDof(newCoordSection, cNew, dof);
408: PetscSectionSetFieldDof(newCoordSection, cNew, 0, dof);
409: }
410: }
411: for (v = vStartNew; v < vEndNew; ++v) {
412: PetscSectionSetDof(newCoordSection, v, dim);
413: PetscSectionSetFieldDof(newCoordSection, v, 0, dim);
414: }
415: PetscSectionSetUp(newCoordSection);
416: DMSetCoordinateSection(dmNew, PETSC_DETERMINE, newCoordSection);
417: PetscSectionGetStorageSize(newCoordSection, &coordSize);
418: VecCreate(PETSC_COMM_SELF, &newCoordinates);
419: PetscObjectSetName((PetscObject) newCoordinates, "coordinates");
420: VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);
421: VecSetBlockSize(newCoordinates, dim);
422: VecSetType(newCoordinates,VECSTANDARD);
423: DMSetCoordinatesLocal(dmNew, newCoordinates);
424: DMGetCoordinatesLocal(dm, &coordinates);
425: VecGetArray(coordinates, &coords);
426: VecGetArray(newCoordinates, &newCoords);
427: if (hasCells) {
428: for (c = cStart; c < cEnd; ++c) {
429: PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof, off, noff, d;
431: PetscSectionGetDof(coordSection, c, &dof);
432: PetscSectionGetOffset(coordSection, c, &off);
433: PetscSectionGetOffset(newCoordSection, cNew, &noff);
434: for (d = 0; d < dof; ++d) newCoords[noff+d] = coords[off+d];
435: }
436: }
437: for (v = vStart; v < vEnd; ++v) {
438: PetscInt dof, off, noff, d;
440: PetscSectionGetDof(coordSection, v, &dof);
441: PetscSectionGetOffset(coordSection, v, &off);
442: PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Internal(v, depth, depthShift), &noff);
443: for (d = 0; d < dof; ++d) newCoords[noff+d] = coords[off+d];
444: }
445: VecRestoreArray(coordinates, &coords);
446: VecRestoreArray(newCoordinates, &newCoords);
447: VecDestroy(&newCoordinates);
448: PetscSectionDestroy(&newCoordSection);
449: return(0);
450: }
454: static PetscErrorCode DMPlexShiftSF_Internal(DM dm, PetscInt depthShift[], DM dmNew)
455: {
456: PetscInt depth = 0;
457: PetscSF sfPoint, sfPointNew;
458: const PetscSFNode *remotePoints;
459: PetscSFNode *gremotePoints;
460: const PetscInt *localPoints;
461: PetscInt *glocalPoints, *newLocation, *newRemoteLocation;
462: PetscInt numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
463: PetscErrorCode ierr;
466: DMPlexGetDepth(dm, &depth);
467: /* Step 9: Convert pointSF */
468: DMGetPointSF(dm, &sfPoint);
469: DMGetPointSF(dmNew, &sfPointNew);
470: DMPlexGetChart(dm, &pStart, &pEnd);
471: PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
472: totShift = DMPlexShiftPoint_Internal(pEnd,depth,depthShift) - pEnd;
473: if (numRoots >= 0) {
474: PetscMalloc2(numRoots,&newLocation,pEnd-pStart,&newRemoteLocation);
475: for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Internal(l, depth, depthShift);
476: PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);
477: PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);
478: PetscMalloc1(numLeaves, &glocalPoints);
479: PetscMalloc1(numLeaves, &gremotePoints);
480: for (l = 0; l < numLeaves; ++l) {
481: glocalPoints[l] = DMPlexShiftPoint_Internal(localPoints[l], depth, depthShift);
482: gremotePoints[l].rank = remotePoints[l].rank;
483: gremotePoints[l].index = newRemoteLocation[localPoints[l]];
484: }
485: PetscFree2(newLocation,newRemoteLocation);
486: PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);
487: }
488: return(0);
489: }
493: static PetscErrorCode DMPlexShiftLabels_Internal(DM dm, PetscInt depthShift[], DM dmNew)
494: {
495: PetscSF sfPoint;
496: DMLabel vtkLabel, ghostLabel;
497: const PetscSFNode *leafRemote;
498: const PetscInt *leafLocal;
499: PetscInt depth = 0, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
500: PetscMPIInt rank;
501: PetscErrorCode ierr;
504: DMPlexGetDepth(dm, &depth);
505: /* Step 10: Convert labels */
506: DMGetNumLabels(dm, &numLabels);
507: for (l = 0; l < numLabels; ++l) {
508: DMLabel label, newlabel;
509: const char *lname;
510: PetscBool isDepth;
511: IS valueIS;
512: const PetscInt *values;
513: PetscInt numValues, val;
515: DMGetLabelName(dm, l, &lname);
516: PetscStrcmp(lname, "depth", &isDepth);
517: if (isDepth) continue;
518: DMCreateLabel(dmNew, lname);
519: DMGetLabel(dm, lname, &label);
520: DMGetLabel(dmNew, lname, &newlabel);
521: DMLabelGetDefaultValue(label,&val);
522: DMLabelSetDefaultValue(newlabel,val);
523: DMLabelGetValueIS(label, &valueIS);
524: ISGetLocalSize(valueIS, &numValues);
525: ISGetIndices(valueIS, &values);
526: for (val = 0; val < numValues; ++val) {
527: IS pointIS;
528: const PetscInt *points;
529: PetscInt numPoints, p;
531: DMLabelGetStratumIS(label, values[val], &pointIS);
532: ISGetLocalSize(pointIS, &numPoints);
533: ISGetIndices(pointIS, &points);
534: for (p = 0; p < numPoints; ++p) {
535: const PetscInt newpoint = DMPlexShiftPoint_Internal(points[p], depth, depthShift);
537: DMLabelSetValue(newlabel, newpoint, values[val]);
538: }
539: ISRestoreIndices(pointIS, &points);
540: ISDestroy(&pointIS);
541: }
542: ISRestoreIndices(valueIS, &values);
543: ISDestroy(&valueIS);
544: }
545: /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
546: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
547: DMGetPointSF(dm, &sfPoint);
548: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
549: PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);
550: DMCreateLabel(dmNew, "vtk");
551: DMCreateLabel(dmNew, "ghost");
552: DMGetLabel(dmNew, "vtk", &vtkLabel);
553: DMGetLabel(dmNew, "ghost", &ghostLabel);
554: for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
555: for (; c < leafLocal[l] && c < cEnd; ++c) {
556: DMLabelSetValue(vtkLabel, c, 1);
557: }
558: if (leafLocal[l] >= cEnd) break;
559: if (leafRemote[l].rank == rank) {
560: DMLabelSetValue(vtkLabel, c, 1);
561: } else {
562: DMLabelSetValue(ghostLabel, c, 2);
563: }
564: }
565: for (; c < cEnd; ++c) {
566: DMLabelSetValue(vtkLabel, c, 1);
567: }
568: if (0) {
569: DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);
570: }
571: DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);
572: for (f = fStart; f < fEnd; ++f) {
573: PetscInt numCells;
575: DMPlexGetSupportSize(dmNew, f, &numCells);
576: if (numCells < 2) {
577: DMLabelSetValue(ghostLabel, f, 1);
578: } else {
579: const PetscInt *cells = NULL;
580: PetscInt vA, vB;
582: DMPlexGetSupport(dmNew, f, &cells);
583: DMLabelGetValue(vtkLabel, cells[0], &vA);
584: DMLabelGetValue(vtkLabel, cells[1], &vB);
585: if (!vA && !vB) {DMLabelSetValue(ghostLabel, f, 1);}
586: }
587: }
588: if (0) {
589: DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);
590: }
591: return(0);
592: }
596: static PetscErrorCode DMPlexShiftTree_Internal(DM dm, PetscInt depthShift[], DM dmNew)
597: {
598: DM refTree;
599: PetscSection pSec;
600: PetscInt *parents, *childIDs;
604: DMPlexGetReferenceTree(dm,&refTree);
605: DMPlexSetReferenceTree(dmNew,refTree);
606: DMPlexGetTree(dm,&pSec,&parents,&childIDs,NULL,NULL);
607: if (pSec) {
608: PetscInt p, pStart, pEnd, *parentsShifted, pStartShifted, pEndShifted, depth;
609: PetscInt *childIDsShifted;
610: PetscSection pSecShifted;
612: PetscSectionGetChart(pSec,&pStart,&pEnd);
613: DMPlexGetDepth(dm,&depth);
614: pStartShifted = DMPlexShiftPoint_Internal(pStart,depth,depthShift);
615: pEndShifted = DMPlexShiftPoint_Internal(pEnd,depth,depthShift);
616: PetscMalloc2(pEndShifted - pStartShifted,&parentsShifted,pEndShifted-pStartShifted,&childIDsShifted);
617: PetscSectionCreate(PetscObjectComm((PetscObject)dmNew),&pSecShifted);
618: PetscSectionSetChart(pSecShifted,pStartShifted,pEndShifted);
619: for (p = pStartShifted; p < pEndShifted; p++) {
620: /* start off assuming no children */
621: PetscSectionSetDof(pSecShifted,p,0);
622: }
623: for (p = pStart; p < pEnd; p++) {
624: PetscInt dof;
625: PetscInt pNew = DMPlexShiftPoint_Internal(p,depth,depthShift);
627: PetscSectionGetDof(pSec,p,&dof);
628: PetscSectionSetDof(pSecShifted,pNew,dof);
629: }
630: PetscSectionSetUp(pSecShifted);
631: for (p = pStart; p < pEnd; p++) {
632: PetscInt dof;
633: PetscInt pNew = DMPlexShiftPoint_Internal(p,depth,depthShift);
635: PetscSectionGetDof(pSec,p,&dof);
636: if (dof) {
637: PetscInt off, offNew;
639: PetscSectionGetOffset(pSec,p,&off);
640: PetscSectionGetOffset(pSecShifted,pNew,&offNew);
641: parentsShifted[offNew] = DMPlexShiftPoint_Internal(parents[off],depth,depthShift);
642: childIDsShifted[offNew] = childIDs[off];
643: }
644: }
645: DMPlexSetTree(dmNew,pSecShifted,parentsShifted,childIDsShifted);
646: PetscFree2(parentsShifted,childIDsShifted);
647: PetscSectionDestroy(&pSecShifted);
648: }
649: return(0);
650: }
654: static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, DMLabel label, PetscInt *numGhostCells, DM gdm)
655: {
656: PetscSF sf;
657: IS valueIS;
658: const PetscInt *values, *leaves;
659: PetscInt *depthShift;
660: PetscInt d, depth = 0, nleaves, loc, Ng, numFS, fs, fStart, fEnd, ghostCell, cEnd, c;
661: PetscErrorCode ierr;
664: DMGetPointSF(dm, &sf);
665: PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
666: nleaves = PetscMax(0, nleaves);
667: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
668: /* Count ghost cells */
669: DMLabelGetValueIS(label, &valueIS);
670: ISGetLocalSize(valueIS, &numFS);
671: ISGetIndices(valueIS, &values);
672: Ng = 0;
673: for (fs = 0; fs < numFS; ++fs) {
674: IS faceIS;
675: const PetscInt *faces;
676: PetscInt numFaces, f, numBdFaces = 0;
678: DMLabelGetStratumIS(label, values[fs], &faceIS);
679: ISGetLocalSize(faceIS, &numFaces);
680: ISGetIndices(faceIS, &faces);
681: for (f = 0; f < numFaces; ++f) {
682: PetscInt numChildren;
684: PetscFindInt(faces[f], nleaves, leaves, &loc);
685: DMPlexGetTreeChildren(dm,faces[f],&numChildren,NULL);
686: /* non-local and ancestors points don't get to register ghosts */
687: if (loc >= 0 || numChildren) continue;
688: if ((faces[f] >= fStart) && (faces[f] < fEnd)) ++numBdFaces;
689: }
690: Ng += numBdFaces;
691: ISDestroy(&faceIS);
692: }
693: DMPlexGetDepth(dm, &depth);
694: PetscMalloc1(2*(depth+1), &depthShift);
695: for (d = 0; d <= depth; d++) {
696: PetscInt dEnd;
698: DMPlexGetDepthStratum(dm,d,NULL,&dEnd);
699: depthShift[2*d] = dEnd;
700: depthShift[2*d+1] = 0;
701: }
702: if (depth >= 0) depthShift[2*depth+1] = Ng;
703: DMPlexShiftPointSetUp_Internal(depth,depthShift);
704: DMPlexShiftSizes_Internal(dm, depthShift, gdm);
705: /* Step 3: Set cone/support sizes for new points */
706: DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
707: DMPlexSetHybridBounds(gdm, cEnd, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_DETERMINE);
708: for (c = cEnd; c < cEnd + Ng; ++c) {
709: DMPlexSetConeSize(gdm, c, 1);
710: }
711: for (fs = 0; fs < numFS; ++fs) {
712: IS faceIS;
713: const PetscInt *faces;
714: PetscInt numFaces, f;
716: DMLabelGetStratumIS(label, values[fs], &faceIS);
717: ISGetLocalSize(faceIS, &numFaces);
718: ISGetIndices(faceIS, &faces);
719: for (f = 0; f < numFaces; ++f) {
720: PetscInt size, numChildren;
722: PetscFindInt(faces[f], nleaves, leaves, &loc);
723: DMPlexGetTreeChildren(dm,faces[f],&numChildren,NULL);
724: if (loc >= 0 || numChildren) continue;
725: if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
726: DMPlexGetSupportSize(dm, faces[f], &size);
727: if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
728: DMPlexSetSupportSize(gdm, faces[f] + Ng, 2);
729: }
730: ISRestoreIndices(faceIS, &faces);
731: ISDestroy(&faceIS);
732: }
733: /* Step 4: Setup ghosted DM */
734: DMSetUp(gdm);
735: DMPlexShiftPoints_Internal(dm, depthShift, gdm);
736: /* Step 6: Set cones and supports for new points */
737: ghostCell = cEnd;
738: for (fs = 0; fs < numFS; ++fs) {
739: IS faceIS;
740: const PetscInt *faces;
741: PetscInt numFaces, f;
743: DMLabelGetStratumIS(label, values[fs], &faceIS);
744: ISGetLocalSize(faceIS, &numFaces);
745: ISGetIndices(faceIS, &faces);
746: for (f = 0; f < numFaces; ++f) {
747: PetscInt newFace = faces[f] + Ng, numChildren;
749: PetscFindInt(faces[f], nleaves, leaves, &loc);
750: DMPlexGetTreeChildren(dm,faces[f],&numChildren,NULL);
751: if (loc >= 0 || numChildren) continue;
752: if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
753: DMPlexSetCone(gdm, ghostCell, &newFace);
754: DMPlexInsertSupport(gdm, newFace, 1, ghostCell);
755: ++ghostCell;
756: }
757: ISRestoreIndices(faceIS, &faces);
758: ISDestroy(&faceIS);
759: }
760: ISRestoreIndices(valueIS, &values);
761: ISDestroy(&valueIS);
762: /* Step 7: Stratify */
763: DMPlexStratify(gdm);
764: DMPlexShiftCoordinates_Internal(dm, depthShift, gdm);
765: DMPlexShiftSF_Internal(dm, depthShift, gdm);
766: DMPlexShiftLabels_Internal(dm, depthShift, gdm);
767: DMPlexShiftTree_Internal(dm, depthShift, gdm);
768: PetscFree(depthShift);
769: /* Step 7: Periodicity */
770: if (dm->maxCell) {
771: const PetscReal *maxCell, *L;
772: const DMBoundaryType *bd;
773: DMGetPeriodicity(dm, &maxCell, &L, &bd);
774: DMSetPeriodicity(gdm, maxCell, L, bd);
775: }
776: if (numGhostCells) *numGhostCells = Ng;
777: return(0);
778: }
782: /*@C
783: DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
785: Collective on dm
787: Input Parameters:
788: + dm - The original DM
789: - labelName - The label specifying the boundary faces, or "Face Sets" if this is NULL
791: Output Parameters:
792: + numGhostCells - The number of ghost cells added to the DM
793: - dmGhosted - The new DM
795: Note: If no label exists of that name, one will be created marking all boundary faces
797: Level: developer
799: .seealso: DMCreate()
800: @*/
801: PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
802: {
803: DM gdm;
804: DMLabel label;
805: const char *name = labelName ? labelName : "Face Sets";
806: PetscInt dim;
807: PetscBool flag;
814: DMCreate(PetscObjectComm((PetscObject)dm), &gdm);
815: DMSetType(gdm, DMPLEX);
816: DMGetDimension(dm, &dim);
817: DMSetDimension(gdm, dim);
818: DMPlexGetAdjacencyUseCone(dm, &flag);
819: DMPlexSetAdjacencyUseCone(gdm, flag);
820: DMPlexGetAdjacencyUseClosure(dm, &flag);
821: DMPlexSetAdjacencyUseClosure(gdm, flag);
822: DMGetLabel(dm, name, &label);
823: if (!label) {
824: /* Get label for boundary faces */
825: DMCreateLabel(dm, name);
826: DMGetLabel(dm, name, &label);
827: DMPlexMarkBoundaryFaces(dm, label);
828: }
829: DMPlexConstructGhostCells_Internal(dm, label, numGhostCells, gdm);
830: DMCopyBoundary(dm, gdm);
831: *dmGhosted = gdm;
832: return(0);
833: }
837: /*
838: We are adding three kinds of points here:
839: Replicated: Copies of points which exist in the mesh, such as vertices identified across a fault
840: Non-replicated: Points which exist on the fault, but are not replicated
841: Hybrid: Entirely new points, such as cohesive cells
843: When creating subsequent cohesive cells, we shift the old hybrid cells to the end of the numbering at
844: each depth so that the new split/hybrid points can be inserted as a block.
845: */
846: static PetscErrorCode DMPlexConstructCohesiveCells_Internal(DM dm, DMLabel label, DM sdm)
847: {
848: MPI_Comm comm;
849: IS valueIS;
850: PetscInt numSP = 0; /* The number of depths for which we have replicated points */
851: const PetscInt *values; /* List of depths for which we have replicated points */
852: IS *splitIS;
853: IS *unsplitIS;
854: PetscInt *numSplitPoints; /* The number of replicated points at each depth */
855: PetscInt *numUnsplitPoints; /* The number of non-replicated points at each depth which still give rise to hybrid points */
856: PetscInt *numHybridPoints; /* The number of new hybrid points at each depth */
857: PetscInt *numHybridPointsOld; /* The number of existing hybrid points at each depth */
858: const PetscInt **splitPoints; /* Replicated points for each depth */
859: const PetscInt **unsplitPoints; /* Non-replicated points for each depth */
860: PetscSection coordSection;
861: Vec coordinates;
862: PetscScalar *coords;
863: PetscInt *depthMax; /* The first hybrid point at each depth in the original mesh */
864: PetscInt *depthEnd; /* The point limit at each depth in the original mesh */
865: PetscInt *depthShift; /* Number of replicated+hybrid points at each depth */
866: PetscInt *pMaxNew; /* The first replicated point at each depth in the new mesh, hybrids come after this */
867: PetscInt *coneNew, *coneONew, *supportNew;
868: PetscInt shift = 100, shift2 = 200, depth = 0, dep, dim, d, sp, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, numLabels, vStart, vEnd, pEnd, p, v;
869: PetscErrorCode ierr;
872: PetscObjectGetComm((PetscObject)dm,&comm);
873: DMGetDimension(dm, &dim);
874: DMPlexGetDepth(dm, &depth);
875: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
876: /* Count split points and add cohesive cells */
877: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
878: PetscMalloc5(depth+1,&depthMax,depth+1,&depthEnd,2*(depth+1),&depthShift,depth+1,&pMaxNew,depth+1,&numHybridPointsOld);
879: PetscMalloc7(depth+1,&splitIS,depth+1,&unsplitIS,depth+1,&numSplitPoints,depth+1,&numUnsplitPoints,depth+1,&numHybridPoints,depth+1,&splitPoints,depth+1,&unsplitPoints);
880: DMPlexGetHybridBounds(dm, depth >= 0 ? &depthMax[depth] : NULL, depth>1 ? &depthMax[depth-1] : NULL, depth>2 ? &depthMax[1] : NULL, depth >= 0 ? &depthMax[0] : NULL);
881: for (d = 0; d <= depth; ++d) {
882: DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);
883: depthEnd[d] = pMaxNew[d];
884: depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
885: numSplitPoints[d] = 0;
886: numUnsplitPoints[d] = 0;
887: numHybridPoints[d] = 0;
888: numHybridPointsOld[d] = depthMax[d] < 0 ? 0 : depthEnd[d] - depthMax[d];
889: splitPoints[d] = NULL;
890: unsplitPoints[d] = NULL;
891: splitIS[d] = NULL;
892: unsplitIS[d] = NULL;
893: /* we are shifting the existing hybrid points with the stratum behind them, so
894: * the split comes at the end of the normal points, i.e., at depthMax[d] */
895: depthShift[2*d] = depthMax[d];
896: depthShift[2*d+1] = 0;
897: }
898: if (label) {
899: DMLabelGetValueIS(label, &valueIS);
900: ISGetLocalSize(valueIS, &numSP);
901: ISGetIndices(valueIS, &values);
902: }
903: for (sp = 0; sp < numSP; ++sp) {
904: const PetscInt dep = values[sp];
906: if ((dep < 0) || (dep > depth)) continue;
907: DMLabelGetStratumIS(label, dep, &splitIS[dep]);
908: if (splitIS[dep]) {
909: ISGetLocalSize(splitIS[dep], &numSplitPoints[dep]);
910: ISGetIndices(splitIS[dep], &splitPoints[dep]);
911: }
912: DMLabelGetStratumIS(label, shift2+dep, &unsplitIS[dep]);
913: if (unsplitIS[dep]) {
914: ISGetLocalSize(unsplitIS[dep], &numUnsplitPoints[dep]);
915: ISGetIndices(unsplitIS[dep], &unsplitPoints[dep]);
916: }
917: }
918: /* Calculate number of hybrid points */
919: 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 */
920: for (d = 0; d <= depth; ++d) depthShift[2*d+1] = numSplitPoints[d] + numHybridPoints[d];
921: DMPlexShiftPointSetUp_Internal(depth,depthShift);
922: /* the end of the points in this stratum that come before the new points:
923: * shifting pMaxNew[d] gets the new start of the next stratum, then count back the old hybrid points and the newly
924: * added points */
925: for (d = 0; d <= depth; ++d) pMaxNew[d] = DMPlexShiftPoint_Internal(pMaxNew[d],depth,depthShift) - (numHybridPointsOld[d] + numSplitPoints[d] + numHybridPoints[d]);
926: DMPlexShiftSizes_Internal(dm, depthShift, sdm);
927: /* Step 3: Set cone/support sizes for new points */
928: for (dep = 0; dep <= depth; ++dep) {
929: for (p = 0; p < numSplitPoints[dep]; ++p) {
930: const PetscInt oldp = splitPoints[dep][p];
931: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
932: const PetscInt splitp = p + pMaxNew[dep];
933: const PetscInt *support;
934: PetscInt coneSize, supportSize, qf, qn, qp, e;
936: DMPlexGetConeSize(dm, oldp, &coneSize);
937: DMPlexSetConeSize(sdm, splitp, coneSize);
938: DMPlexGetSupportSize(dm, oldp, &supportSize);
939: DMPlexSetSupportSize(sdm, splitp, supportSize);
940: if (dep == depth-1) {
941: const PetscInt hybcell = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
943: /* Add cohesive cells, they are prisms */
944: DMPlexSetConeSize(sdm, hybcell, 2 + coneSize);
945: } else if (dep == 0) {
946: const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
948: DMPlexGetSupport(dm, oldp, &support);
949: for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
950: PetscInt val;
952: DMLabelGetValue(label, support[e], &val);
953: if (val == 1) ++qf;
954: if ((val == 1) || (val == (shift + 1))) ++qn;
955: if ((val == 1) || (val == -(shift + 1))) ++qp;
956: }
957: /* Split old vertex: Edges into original vertex and new cohesive edge */
958: DMPlexSetSupportSize(sdm, newp, qn+1);
959: /* Split new vertex: Edges into split vertex and new cohesive edge */
960: DMPlexSetSupportSize(sdm, splitp, qp+1);
961: /* Add hybrid edge */
962: DMPlexSetConeSize(sdm, hybedge, 2);
963: DMPlexSetSupportSize(sdm, hybedge, qf);
964: } else if (dep == dim-2) {
965: const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
967: DMPlexGetSupport(dm, oldp, &support);
968: for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
969: PetscInt val;
971: DMLabelGetValue(label, support[e], &val);
972: if (val == dim-1) ++qf;
973: if ((val == dim-1) || (val == (shift + dim-1))) ++qn;
974: if ((val == dim-1) || (val == -(shift + dim-1))) ++qp;
975: }
976: /* Split old edge: Faces into original edge and cohesive face (positive side?) */
977: DMPlexSetSupportSize(sdm, newp, qn+1);
978: /* Split new edge: Faces into split edge and cohesive face (negative side?) */
979: DMPlexSetSupportSize(sdm, splitp, qp+1);
980: /* Add hybrid face */
981: DMPlexSetConeSize(sdm, hybface, 4);
982: DMPlexSetSupportSize(sdm, hybface, qf);
983: }
984: }
985: }
986: for (dep = 0; dep <= depth; ++dep) {
987: for (p = 0; p < numUnsplitPoints[dep]; ++p) {
988: const PetscInt oldp = unsplitPoints[dep][p];
989: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
990: const PetscInt *support;
991: PetscInt coneSize, supportSize, qf, e, s;
993: DMPlexGetConeSize(dm, oldp, &coneSize);
994: DMPlexGetSupportSize(dm, oldp, &supportSize);
995: DMPlexGetSupport(dm, oldp, &support);
996: if (dep == 0) {
997: const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];
999: /* Unsplit vertex: Edges into original vertex, split edges, and new cohesive edge twice */
1000: for (s = 0, qf = 0; s < supportSize; ++s, ++qf) {
1001: PetscFindInt(support[s], numSplitPoints[dep+1], splitPoints[dep+1], &e);
1002: if (e >= 0) ++qf;
1003: }
1004: DMPlexSetSupportSize(sdm, newp, qf+2);
1005: /* Add hybrid edge */
1006: DMPlexSetConeSize(sdm, hybedge, 2);
1007: for (e = 0, qf = 0; e < supportSize; ++e) {
1008: PetscInt val;
1010: DMLabelGetValue(label, support[e], &val);
1011: /* Split and unsplit edges produce hybrid faces */
1012: if (val == 1) ++qf;
1013: if (val == (shift2 + 1)) ++qf;
1014: }
1015: DMPlexSetSupportSize(sdm, hybedge, qf);
1016: } else if (dep == dim-2) {
1017: const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];
1018: PetscInt val;
1020: for (e = 0, qf = 0; e < supportSize; ++e) {
1021: DMLabelGetValue(label, support[e], &val);
1022: if (val == dim-1) qf += 2;
1023: else ++qf;
1024: }
1025: /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */
1026: DMPlexSetSupportSize(sdm, newp, qf+2);
1027: /* Add hybrid face */
1028: for (e = 0, qf = 0; e < supportSize; ++e) {
1029: DMLabelGetValue(label, support[e], &val);
1030: if (val == dim-1) ++qf;
1031: }
1032: DMPlexSetConeSize(sdm, hybface, 4);
1033: DMPlexSetSupportSize(sdm, hybface, qf);
1034: }
1035: }
1036: }
1037: /* Step 4: Setup split DM */
1038: DMSetUp(sdm);
1039: DMPlexShiftPoints_Internal(dm, depthShift, sdm);
1040: DMPlexGetMaxSizes(sdm, &maxConeSizeNew, &maxSupportSizeNew);
1041: PetscMalloc3(PetscMax(maxConeSize, maxConeSizeNew)*3,&coneNew,PetscMax(maxConeSize, maxConeSizeNew)*3,&coneONew,PetscMax(maxSupportSize, maxSupportSizeNew),&supportNew);
1042: /* Step 6: Set cones and supports for new points */
1043: for (dep = 0; dep <= depth; ++dep) {
1044: for (p = 0; p < numSplitPoints[dep]; ++p) {
1045: const PetscInt oldp = splitPoints[dep][p];
1046: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1047: const PetscInt splitp = p + pMaxNew[dep];
1048: const PetscInt *cone, *support, *ornt;
1049: PetscInt coneSize, supportSize, q, qf, qn, qp, v, e, s;
1051: DMPlexGetConeSize(dm, oldp, &coneSize);
1052: DMPlexGetCone(dm, oldp, &cone);
1053: DMPlexGetConeOrientation(dm, oldp, &ornt);
1054: DMPlexGetSupportSize(dm, oldp, &supportSize);
1055: DMPlexGetSupport(dm, oldp, &support);
1056: if (dep == depth-1) {
1057: PetscBool hasUnsplit = PETSC_FALSE;
1058: const PetscInt hybcell = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1059: const PetscInt *supportF;
1061: /* Split face: copy in old face to new face to start */
1062: DMPlexGetSupport(sdm, newp, &supportF);
1063: DMPlexSetSupport(sdm, splitp, supportF);
1064: /* Split old face: old vertices/edges in cone so no change */
1065: /* Split new face: new vertices/edges in cone */
1066: for (q = 0; q < coneSize; ++q) {
1067: PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v);
1068: if (v < 0) {
1069: PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1070: if (v < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", cone[q], dep-1);
1071: coneNew[2+q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/;
1072: hasUnsplit = PETSC_TRUE;
1073: } else {
1074: coneNew[2+q] = v + pMaxNew[dep-1];
1075: if (dep > 1) {
1076: const PetscInt *econe;
1077: PetscInt econeSize, r, vs, vu;
1079: DMPlexGetConeSize(dm, cone[q], &econeSize);
1080: DMPlexGetCone(dm, cone[q], &econe);
1081: for (r = 0; r < econeSize; ++r) {
1082: PetscFindInt(econe[r], numSplitPoints[dep-2], splitPoints[dep-2], &vs);
1083: PetscFindInt(econe[r], numUnsplitPoints[dep-2], unsplitPoints[dep-2], &vu);
1084: if (vs >= 0) continue;
1085: if (vu < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", econe[r], dep-2);
1086: hasUnsplit = PETSC_TRUE;
1087: }
1088: }
1089: }
1090: }
1091: DMPlexSetCone(sdm, splitp, &coneNew[2]);
1092: DMPlexSetConeOrientation(sdm, splitp, ornt);
1093: /* Face support */
1094: for (s = 0; s < supportSize; ++s) {
1095: PetscInt val;
1097: DMLabelGetValue(label, support[s], &val);
1098: if (val < 0) {
1099: /* Split old face: Replace negative side cell with cohesive cell */
1100: DMPlexInsertSupport(sdm, newp, s, hybcell);
1101: } else {
1102: /* Split new face: Replace positive side cell with cohesive cell */
1103: DMPlexInsertSupport(sdm, splitp, s, hybcell);
1104: /* Get orientation for cohesive face */
1105: {
1106: const PetscInt *ncone, *nconeO;
1107: PetscInt nconeSize, nc;
1109: DMPlexGetConeSize(dm, support[s], &nconeSize);
1110: DMPlexGetCone(dm, support[s], &ncone);
1111: DMPlexGetConeOrientation(dm, support[s], &nconeO);
1112: for (nc = 0; nc < nconeSize; ++nc) {
1113: if (ncone[nc] == oldp) {
1114: coneONew[0] = nconeO[nc];
1115: break;
1116: }
1117: }
1118: if (nc >= nconeSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate face %d in neighboring cell %d", oldp, support[s]);
1119: }
1120: }
1121: }
1122: /* Cohesive cell: Old and new split face, then new cohesive faces */
1123: coneNew[0] = newp; /* Extracted negative side orientation above */
1124: coneNew[1] = splitp;
1125: coneONew[1] = coneONew[0];
1126: for (q = 0; q < coneSize; ++q) {
1127: PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v);
1128: if (v < 0) {
1129: PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1130: coneNew[2+q] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
1131: coneONew[2+q] = 0;
1132: } else {
1133: coneNew[2+q] = v + pMaxNew[dep] + numSplitPoints[dep];
1134: }
1135: coneONew[2+q] = 0;
1136: }
1137: DMPlexSetCone(sdm, hybcell, coneNew);
1138: DMPlexSetConeOrientation(sdm, hybcell, coneONew);
1139: /* Label the hybrid cells on the boundary of the split */
1140: if (hasUnsplit) {DMLabelSetValue(label, -hybcell, dim);}
1141: } else if (dep == 0) {
1142: const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1144: /* Split old vertex: Edges in old split faces and new cohesive edge */
1145: for (e = 0, qn = 0; e < supportSize; ++e) {
1146: PetscInt val;
1148: DMLabelGetValue(label, support[e], &val);
1149: if ((val == 1) || (val == (shift + 1))) {
1150: supportNew[qn++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1151: }
1152: }
1153: supportNew[qn] = hybedge;
1154: DMPlexSetSupport(sdm, newp, supportNew);
1155: /* Split new vertex: Edges in new split faces and new cohesive edge */
1156: for (e = 0, qp = 0; e < supportSize; ++e) {
1157: PetscInt val, edge;
1159: DMLabelGetValue(label, support[e], &val);
1160: if (val == 1) {
1161: PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge);
1162: if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
1163: supportNew[qp++] = edge + pMaxNew[dep+1];
1164: } else if (val == -(shift + 1)) {
1165: supportNew[qp++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1166: }
1167: }
1168: supportNew[qp] = hybedge;
1169: DMPlexSetSupport(sdm, splitp, supportNew);
1170: /* Hybrid edge: Old and new split vertex */
1171: coneNew[0] = newp;
1172: coneNew[1] = splitp;
1173: DMPlexSetCone(sdm, hybedge, coneNew);
1174: for (e = 0, qf = 0; e < supportSize; ++e) {
1175: PetscInt val, edge;
1177: DMLabelGetValue(label, support[e], &val);
1178: if (val == 1) {
1179: PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge);
1180: if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
1181: supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2];
1182: }
1183: }
1184: DMPlexSetSupport(sdm, hybedge, supportNew);
1185: } else if (dep == dim-2) {
1186: const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1188: /* Split old edge: old vertices in cone so no change */
1189: /* Split new edge: new vertices in cone */
1190: for (q = 0; q < coneSize; ++q) {
1191: PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v);
1192: if (v < 0) {
1193: PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1194: if (v < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", cone[q], dep-1);
1195: coneNew[q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/;
1196: } else {
1197: coneNew[q] = v + pMaxNew[dep-1];
1198: }
1199: }
1200: DMPlexSetCone(sdm, splitp, coneNew);
1201: /* Split old edge: Faces in positive side cells and old split faces */
1202: for (e = 0, q = 0; e < supportSize; ++e) {
1203: PetscInt val;
1205: DMLabelGetValue(label, support[e], &val);
1206: if (val == dim-1) {
1207: supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1208: } else if (val == (shift + dim-1)) {
1209: supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1210: }
1211: }
1212: supportNew[q++] = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1213: DMPlexSetSupport(sdm, newp, supportNew);
1214: /* Split new edge: Faces in negative side cells and new split faces */
1215: for (e = 0, q = 0; e < supportSize; ++e) {
1216: PetscInt val, face;
1218: DMLabelGetValue(label, support[e], &val);
1219: if (val == dim-1) {
1220: PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &face);
1221: if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
1222: supportNew[q++] = face + pMaxNew[dep+1];
1223: } else if (val == -(shift + dim-1)) {
1224: supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1225: }
1226: }
1227: supportNew[q++] = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1228: DMPlexSetSupport(sdm, splitp, supportNew);
1229: /* Hybrid face */
1230: coneNew[0] = newp;
1231: coneNew[1] = splitp;
1232: for (v = 0; v < coneSize; ++v) {
1233: PetscInt vertex;
1234: PetscFindInt(cone[v], numSplitPoints[dep-1], splitPoints[dep-1], &vertex);
1235: if (vertex < 0) {
1236: PetscFindInt(cone[v], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &vertex);
1237: if (vertex < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", cone[v], dep-1);
1238: coneNew[2+v] = vertex + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
1239: } else {
1240: coneNew[2+v] = vertex + pMaxNew[dep] + numSplitPoints[dep];
1241: }
1242: }
1243: DMPlexSetCone(sdm, hybface, coneNew);
1244: for (e = 0, qf = 0; e < supportSize; ++e) {
1245: PetscInt val, face;
1247: DMLabelGetValue(label, support[e], &val);
1248: if (val == dim-1) {
1249: PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &face);
1250: if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
1251: supportNew[qf++] = face + pMaxNew[dep+2] + numSplitPoints[dep+2];
1252: }
1253: }
1254: DMPlexSetSupport(sdm, hybface, supportNew);
1255: }
1256: }
1257: }
1258: for (dep = 0; dep <= depth; ++dep) {
1259: for (p = 0; p < numUnsplitPoints[dep]; ++p) {
1260: const PetscInt oldp = unsplitPoints[dep][p];
1261: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1262: const PetscInt *cone, *support, *ornt;
1263: PetscInt coneSize, supportSize, supportSizeNew, q, qf, e, f, s;
1265: DMPlexGetConeSize(dm, oldp, &coneSize);
1266: DMPlexGetCone(dm, oldp, &cone);
1267: DMPlexGetConeOrientation(dm, oldp, &ornt);
1268: DMPlexGetSupportSize(dm, oldp, &supportSize);
1269: DMPlexGetSupport(dm, oldp, &support);
1270: if (dep == 0) {
1271: const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];
1273: /* Unsplit vertex */
1274: DMPlexGetSupportSize(sdm, newp, &supportSizeNew);
1275: for (s = 0, q = 0; s < supportSize; ++s) {
1276: supportNew[q++] = DMPlexShiftPoint_Internal(support[s], depth, depthShift) /*support[s] + depthOffset[dep+1]*/;
1277: PetscFindInt(support[s], numSplitPoints[dep+1], splitPoints[dep+1], &e);
1278: if (e >= 0) {
1279: supportNew[q++] = e + pMaxNew[dep+1];
1280: }
1281: }
1282: supportNew[q++] = hybedge;
1283: supportNew[q++] = hybedge;
1284: if (q != supportSizeNew) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Support size %d != %d for vertex %d", q, supportSizeNew, newp);
1285: DMPlexSetSupport(sdm, newp, supportNew);
1286: /* Hybrid edge */
1287: coneNew[0] = newp;
1288: coneNew[1] = newp;
1289: DMPlexSetCone(sdm, hybedge, coneNew);
1290: for (e = 0, qf = 0; e < supportSize; ++e) {
1291: PetscInt val, edge;
1293: DMLabelGetValue(label, support[e], &val);
1294: if (val == 1) {
1295: PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge);
1296: if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
1297: supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2];
1298: } else if (val == (shift2 + 1)) {
1299: PetscFindInt(support[e], numUnsplitPoints[dep+1], unsplitPoints[dep+1], &edge);
1300: if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a unsplit edge", support[e]);
1301: supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2] + numSplitPoints[dep+1];
1302: }
1303: }
1304: DMPlexSetSupport(sdm, hybedge, supportNew);
1305: } else if (dep == dim-2) {
1306: const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];
1308: /* Unsplit edge: Faces into original edge, split face, and hybrid face twice */
1309: for (f = 0, qf = 0; f < supportSize; ++f) {
1310: PetscInt val, face;
1312: DMLabelGetValue(label, support[f], &val);
1313: if (val == dim-1) {
1314: PetscFindInt(support[f], numSplitPoints[dep+1], splitPoints[dep+1], &face);
1315: if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[f]);
1316: supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/;
1317: supportNew[qf++] = face + pMaxNew[dep+1];
1318: } else {
1319: supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/;
1320: }
1321: }
1322: supportNew[qf++] = hybface;
1323: supportNew[qf++] = hybface;
1324: DMPlexGetSupportSize(sdm, newp, &supportSizeNew);
1325: if (qf != supportSizeNew) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for unsplit edge %d is %d != %d\n", newp, qf, supportSizeNew);
1326: DMPlexSetSupport(sdm, newp, supportNew);
1327: /* Add hybrid face */
1328: coneNew[0] = newp;
1329: coneNew[1] = newp;
1330: PetscFindInt(cone[0], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1331: if (v < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex %d is not an unsplit vertex", cone[0]);
1332: coneNew[2] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
1333: PetscFindInt(cone[1], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1334: if (v < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex %d is not an unsplit vertex", cone[1]);
1335: coneNew[3] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
1336: DMPlexSetCone(sdm, hybface, coneNew);
1337: for (f = 0, qf = 0; f < supportSize; ++f) {
1338: PetscInt val, face;
1340: DMLabelGetValue(label, support[f], &val);
1341: if (val == dim-1) {
1342: PetscFindInt(support[f], numSplitPoints[dep+1], splitPoints[dep+1], &face);
1343: supportNew[qf++] = face + pMaxNew[dep+2] + numSplitPoints[dep+2];
1344: }
1345: }
1346: DMPlexGetSupportSize(sdm, hybface, &supportSizeNew);
1347: if (qf != supportSizeNew) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for hybrid face %d is %d != %d\n", hybface, qf, supportSizeNew);
1348: DMPlexSetSupport(sdm, hybface, supportNew);
1349: }
1350: }
1351: }
1352: /* Step 6b: Replace split points in negative side cones */
1353: for (sp = 0; sp < numSP; ++sp) {
1354: PetscInt dep = values[sp];
1355: IS pIS;
1356: PetscInt numPoints;
1357: const PetscInt *points;
1359: if (dep >= 0) continue;
1360: DMLabelGetStratumIS(label, dep, &pIS);
1361: if (!pIS) continue;
1362: dep = -dep - shift;
1363: ISGetLocalSize(pIS, &numPoints);
1364: ISGetIndices(pIS, &points);
1365: for (p = 0; p < numPoints; ++p) {
1366: const PetscInt oldp = points[p];
1367: const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*depthOffset[dep] + oldp*/;
1368: const PetscInt *cone;
1369: PetscInt coneSize, c;
1370: /* PetscBool replaced = PETSC_FALSE; */
1372: /* Negative edge: replace split vertex */
1373: /* Negative cell: replace split face */
1374: DMPlexGetConeSize(sdm, newp, &coneSize);
1375: DMPlexGetCone(sdm, newp, &cone);
1376: for (c = 0; c < coneSize; ++c) {
1377: const PetscInt coldp = DMPlexShiftPointInverse_Internal(cone[c],depth,depthShift);
1378: PetscInt csplitp, cp, val;
1380: DMLabelGetValue(label, coldp, &val);
1381: if (val == dep-1) {
1382: PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);
1383: if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
1384: csplitp = pMaxNew[dep-1] + cp;
1385: DMPlexInsertCone(sdm, newp, c, csplitp);
1386: /* replaced = PETSC_TRUE; */
1387: }
1388: }
1389: /* Cells with only a vertex or edge on the submesh have no replacement */
1390: /* if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp); */
1391: }
1392: ISRestoreIndices(pIS, &points);
1393: ISDestroy(&pIS);
1394: }
1395: /* Step 7: Stratify */
1396: DMPlexStratify(sdm);
1397: /* Step 8: Coordinates */
1398: DMPlexShiftCoordinates_Internal(dm, depthShift, sdm);
1399: DMGetCoordinateSection(sdm, &coordSection);
1400: DMGetCoordinatesLocal(sdm, &coordinates);
1401: VecGetArray(coordinates, &coords);
1402: for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
1403: const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[0][v], depth, depthShift) /*depthOffset[0] + splitPoints[0][v]*/;
1404: const PetscInt splitp = pMaxNew[0] + v;
1405: PetscInt dof, off, soff, d;
1407: PetscSectionGetDof(coordSection, newp, &dof);
1408: PetscSectionGetOffset(coordSection, newp, &off);
1409: PetscSectionGetOffset(coordSection, splitp, &soff);
1410: for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
1411: }
1412: VecRestoreArray(coordinates, &coords);
1413: /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
1414: DMPlexShiftSF_Internal(dm, depthShift, sdm);
1415: /* Step 10: Labels */
1416: DMPlexShiftLabels_Internal(dm, depthShift, sdm);
1417: DMGetNumLabels(sdm, &numLabels);
1418: for (dep = 0; dep <= depth; ++dep) {
1419: for (p = 0; p < numSplitPoints[dep]; ++p) {
1420: const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[dep][p], depth, depthShift) /*depthOffset[dep] + splitPoints[dep][p]*/;
1421: const PetscInt splitp = pMaxNew[dep] + p;
1422: PetscInt l;
1424: for (l = 0; l < numLabels; ++l) {
1425: DMLabel mlabel;
1426: const char *lname;
1427: PetscInt val;
1428: PetscBool isDepth;
1430: DMGetLabelName(sdm, l, &lname);
1431: PetscStrcmp(lname, "depth", &isDepth);
1432: if (isDepth) continue;
1433: DMGetLabel(sdm, lname, &mlabel);
1434: DMLabelGetValue(mlabel, newp, &val);
1435: if (val >= 0) {
1436: DMLabelSetValue(mlabel, splitp, val);
1437: #if 0
1438: /* Do not put cohesive edges into the label */
1439: if (dep == 0) {
1440: const PetscInt cedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1441: DMLabelSetValue(mlabel, cedge, val);
1442: } else if (dep == dim-2) {
1443: const PetscInt cface = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1444: DMLabelSetValue(mlabel, cface, val);
1445: }
1446: /* Do not put cohesive faces into the label */
1447: #endif
1448: }
1449: }
1450: }
1451: }
1452: for (sp = 0; sp < numSP; ++sp) {
1453: const PetscInt dep = values[sp];
1455: if ((dep < 0) || (dep > depth)) continue;
1456: if (splitIS[dep]) {ISRestoreIndices(splitIS[dep], &splitPoints[dep]);}
1457: ISDestroy(&splitIS[dep]);
1458: if (unsplitIS[dep]) {ISRestoreIndices(unsplitIS[dep], &unsplitPoints[dep]);}
1459: ISDestroy(&unsplitIS[dep]);
1460: }
1461: if (label) {
1462: ISRestoreIndices(valueIS, &values);
1463: ISDestroy(&valueIS);
1464: }
1465: for (d = 0; d <= depth; ++d) {
1466: DMPlexGetDepthStratum(sdm, d, NULL, &pEnd);
1467: pMaxNew[d] = pEnd - numHybridPoints[d] - numHybridPointsOld[d];
1468: }
1469: DMPlexSetHybridBounds(sdm, depth >= 0 ? pMaxNew[depth] : PETSC_DETERMINE, depth>1 ? pMaxNew[depth-1] : PETSC_DETERMINE, depth>2 ? pMaxNew[1] : PETSC_DETERMINE, depth >= 0 ? pMaxNew[0] : PETSC_DETERMINE);
1470: PetscFree3(coneNew, coneONew, supportNew);
1471: PetscFree5(depthMax, depthEnd, depthShift, pMaxNew, numHybridPointsOld);
1472: PetscFree7(splitIS, unsplitIS, numSplitPoints, numUnsplitPoints, numHybridPoints, splitPoints, unsplitPoints);
1473: return(0);
1474: }
1478: /*@C
1479: DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
1481: Collective on dm
1483: Input Parameters:
1484: + dm - The original DM
1485: - label - The label specifying the boundary faces (this could be auto-generated)
1487: Output Parameters:
1488: - dmSplit - The new DM
1490: Level: developer
1492: .seealso: DMCreate(), DMPlexLabelCohesiveComplete()
1493: @*/
1494: PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
1495: {
1496: DM sdm;
1497: PetscInt dim;
1503: DMCreate(PetscObjectComm((PetscObject)dm), &sdm);
1504: DMSetType(sdm, DMPLEX);
1505: DMGetDimension(dm, &dim);
1506: DMSetDimension(sdm, dim);
1507: switch (dim) {
1508: case 2:
1509: case 3:
1510: DMPlexConstructCohesiveCells_Internal(dm, label, sdm);
1511: break;
1512: default:
1513: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
1514: }
1515: *dmSplit = sdm;
1516: return(0);
1517: }
1521: /* Returns the side of the surface for a given cell with a face on the surface */
1522: static PetscErrorCode GetSurfaceSide_Static(DM dm, DM subdm, PetscInt numSubpoints, const PetscInt *subpoints, PetscInt cell, PetscInt face, PetscBool *pos)
1523: {
1524: const PetscInt *cone, *ornt;
1525: PetscInt dim, coneSize, c;
1526: PetscErrorCode ierr;
1529: *pos = PETSC_TRUE;
1530: DMGetDimension(dm, &dim);
1531: DMPlexGetConeSize(dm, cell, &coneSize);
1532: DMPlexGetCone(dm, cell, &cone);
1533: DMPlexGetConeOrientation(dm, cell, &ornt);
1534: for (c = 0; c < coneSize; ++c) {
1535: if (cone[c] == face) {
1536: PetscInt o = ornt[c];
1538: if (subdm) {
1539: const PetscInt *subcone, *subornt;
1540: PetscInt subpoint, subface, subconeSize, sc;
1542: PetscFindInt(cell, numSubpoints, subpoints, &subpoint);
1543: PetscFindInt(face, numSubpoints, subpoints, &subface);
1544: DMPlexGetConeSize(subdm, subpoint, &subconeSize);
1545: DMPlexGetCone(subdm, subpoint, &subcone);
1546: DMPlexGetConeOrientation(subdm, subpoint, &subornt);
1547: for (sc = 0; sc < subconeSize; ++sc) {
1548: if (subcone[sc] == subface) {
1549: o = subornt[0];
1550: break;
1551: }
1552: }
1553: if (sc >= subconeSize) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find subpoint %d (%d) in cone for subpoint %d (%d)", subface, face, subpoint, cell);
1554: }
1555: if (o >= 0) *pos = PETSC_TRUE;
1556: else *pos = PETSC_FALSE;
1557: break;
1558: }
1559: }
1560: if (c == coneSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell %d in split face %d support does not have it in the cone", cell, face);
1561: return(0);
1562: }
1566: /*@
1567: DMPlexLabelCohesiveComplete - Starting with a label marking points on an internal surface, we add all other mesh pieces
1568: to complete the surface
1570: Input Parameters:
1571: + dm - The DM
1572: . label - A DMLabel marking the surface
1573: . blabel - A DMLabel marking the vertices on the boundary which will not be duplicated, or NULL to find them automatically
1574: . flip - Flag to flip the submesh normal and replace points on the other side
1575: - subdm - The subDM associated with the label, or NULL
1577: Output Parameter:
1578: . label - A DMLabel marking all surface points
1580: Note: The vertices in blabel are called "unsplit" in the terminology from hybrid cell creation.
1582: Level: developer
1584: .seealso: DMPlexConstructCohesiveCells(), DMPlexLabelComplete()
1585: @*/
1586: PetscErrorCode DMPlexLabelCohesiveComplete(DM dm, DMLabel label, DMLabel blabel, PetscBool flip, DM subdm)
1587: {
1588: DMLabel depthLabel;
1589: IS dimIS, subpointIS = NULL, facePosIS, faceNegIS, crossEdgeIS = NULL;
1590: const PetscInt *points, *subpoints;
1591: const PetscInt rev = flip ? -1 : 1;
1592: PetscInt *pMax;
1593: PetscInt shift = 100, shift2 = 200, dim, depth, pSize, dep, cStart, cEnd, cMax, fStart, fEnd, vStart, vEnd, numPoints, numSubpoints, p, val;
1594: PetscErrorCode ierr;
1597: DMPlexGetDepth(dm, &depth);
1598: DMGetDimension(dm, &dim);
1599: pSize = PetscMax(depth, dim) + 1;
1600: PetscMalloc1(pSize,&pMax);
1601: DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
1602: DMPlexGetDepthLabel(dm, &depthLabel);
1603: DMGetDimension(dm, &dim);
1604: if (subdm) {
1605: DMPlexCreateSubpointIS(subdm, &subpointIS);
1606: if (subpointIS) {
1607: ISGetLocalSize(subpointIS, &numSubpoints);
1608: ISGetIndices(subpointIS, &subpoints);
1609: }
1610: }
1611: /* Mark cell on the fault, and its faces which touch the fault: cell orientation for face gives the side of the fault */
1612: DMLabelGetStratumIS(label, dim-1, &dimIS);
1613: if (!dimIS) {
1614: PetscFree(pMax);
1615: ISDestroy(&subpointIS);
1616: return(0);
1617: }
1618: ISGetLocalSize(dimIS, &numPoints);
1619: ISGetIndices(dimIS, &points);
1620: for (p = 0; p < numPoints; ++p) { /* Loop over fault faces */
1621: const PetscInt *support;
1622: PetscInt supportSize, s;
1624: DMPlexGetSupportSize(dm, points[p], &supportSize);
1625: if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
1626: DMPlexGetSupport(dm, points[p], &support);
1627: for (s = 0; s < supportSize; ++s) {
1628: const PetscInt *cone;
1629: PetscInt coneSize, c;
1630: PetscBool pos;
1632: GetSurfaceSide_Static(dm, subdm, numSubpoints, subpoints, support[s], points[p], &pos);
1633: if (pos) {DMLabelSetValue(label, support[s], rev*(shift+dim));}
1634: else {DMLabelSetValue(label, support[s], -rev*(shift+dim));}
1635: if (rev < 0) pos = !pos ? PETSC_TRUE : PETSC_FALSE;
1636: /* Put faces touching the fault in the label */
1637: DMPlexGetConeSize(dm, support[s], &coneSize);
1638: DMPlexGetCone(dm, support[s], &cone);
1639: for (c = 0; c < coneSize; ++c) {
1640: const PetscInt point = cone[c];
1642: DMLabelGetValue(label, point, &val);
1643: if (val == -1) {
1644: PetscInt *closure = NULL;
1645: PetscInt closureSize, cl;
1647: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1648: for (cl = 0; cl < closureSize*2; cl += 2) {
1649: const PetscInt clp = closure[cl];
1650: PetscInt bval = -1;
1652: DMLabelGetValue(label, clp, &val);
1653: if (blabel) {DMLabelGetValue(blabel, clp, &bval);}
1654: if ((val >= 0) && (val < dim-1) && (bval < 0)) {
1655: DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));
1656: break;
1657: }
1658: }
1659: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1660: }
1661: }
1662: }
1663: }
1664: ISRestoreIndices(dimIS, &points);
1665: ISDestroy(&dimIS);
1666: if (subpointIS) {ISRestoreIndices(subpointIS, &subpoints);}
1667: ISDestroy(&subpointIS);
1668: /* Mark boundary points as unsplit */
1669: if (blabel) {
1670: DMLabelGetStratumIS(blabel, 1, &dimIS);
1671: ISGetLocalSize(dimIS, &numPoints);
1672: ISGetIndices(dimIS, &points);
1673: for (p = 0; p < numPoints; ++p) {
1674: const PetscInt point = points[p];
1675: PetscInt val, bval;
1677: DMLabelGetValue(blabel, point, &bval);
1678: if (bval >= 0) {
1679: DMLabelGetValue(label, point, &val);
1680: if ((val < 0) || (val > dim)) {
1681: /* This could be a point added from splitting a vertex on an adjacent fault, otherwise its just wrong */
1682: DMLabelClearValue(blabel, point, bval);
1683: }
1684: }
1685: }
1686: for (p = 0; p < numPoints; ++p) {
1687: const PetscInt point = points[p];
1688: PetscInt val, bval;
1690: DMLabelGetValue(blabel, point, &bval);
1691: if (bval >= 0) {
1692: const PetscInt *cone, *support;
1693: PetscInt coneSize, supportSize, s, valA, valB, valE;
1695: /* Mark as unsplit */
1696: DMLabelGetValue(label, point, &val);
1697: if ((val < 0) || (val > dim)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d has label value %d, should be part of the fault", point, val);
1698: DMLabelClearValue(label, point, val);
1699: DMLabelSetValue(label, point, shift2+val);
1700: /* Check for cross-edge
1701: A cross-edge has endpoints which are both on the boundary of the surface, but the edge itself is not. */
1702: if (val != 0) continue;
1703: DMPlexGetSupport(dm, point, &support);
1704: DMPlexGetSupportSize(dm, point, &supportSize);
1705: for (s = 0; s < supportSize; ++s) {
1706: DMPlexGetCone(dm, support[s], &cone);
1707: DMPlexGetConeSize(dm, support[s], &coneSize);
1708: if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D has %D vertices != 2", support[s], coneSize);
1709: DMLabelGetValue(blabel, cone[0], &valA);
1710: DMLabelGetValue(blabel, cone[1], &valB);
1711: DMLabelGetValue(blabel, support[s], &valE);
1712: if ((valE < 0) && (valA >= 0) && (valB >= 0) && (cone[0] != cone[1])) {DMLabelSetValue(blabel, support[s], 2);}
1713: }
1714: }
1715: }
1716: ISRestoreIndices(dimIS, &points);
1717: ISDestroy(&dimIS);
1718: }
1719: /* Search for other cells/faces/edges connected to the fault by a vertex */
1720: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1721: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1722: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
1723: cMax = cMax < 0 ? cEnd : cMax;
1724: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1725: DMLabelGetStratumIS(label, 0, &dimIS);
1726: if (blabel) {DMLabelGetStratumIS(blabel, 2, &crossEdgeIS);}
1727: if (dimIS && crossEdgeIS) {
1728: IS vertIS = dimIS;
1730: ISExpand(vertIS, crossEdgeIS, &dimIS);
1731: ISDestroy(&crossEdgeIS);
1732: ISDestroy(&vertIS);
1733: }
1734: if (!dimIS) {
1735: PetscFree(pMax);
1736: return(0);
1737: }
1738: ISGetLocalSize(dimIS, &numPoints);
1739: ISGetIndices(dimIS, &points);
1740: for (p = 0; p < numPoints; ++p) { /* Loop over fault vertices */
1741: PetscInt *star = NULL;
1742: PetscInt starSize, s;
1743: PetscInt again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */
1745: /* All points connected to the fault are inside a cell, so at the top level we will only check cells */
1746: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);
1747: while (again) {
1748: if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
1749: again = 0;
1750: for (s = 0; s < starSize*2; s += 2) {
1751: const PetscInt point = star[s];
1752: const PetscInt *cone;
1753: PetscInt coneSize, c;
1755: if ((point < cStart) || (point >= cMax)) continue;
1756: DMLabelGetValue(label, point, &val);
1757: if (val != -1) continue;
1758: again = again == 1 ? 1 : 2;
1759: DMPlexGetConeSize(dm, point, &coneSize);
1760: DMPlexGetCone(dm, point, &cone);
1761: for (c = 0; c < coneSize; ++c) {
1762: DMLabelGetValue(label, cone[c], &val);
1763: if (val != -1) {
1764: const PetscInt *ccone;
1765: PetscInt cconeSize, cc, side;
1767: if (PetscAbs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
1768: if (val > 0) side = 1;
1769: else side = -1;
1770: DMLabelSetValue(label, point, side*(shift+dim));
1771: /* Mark cell faces which touch the fault */
1772: DMPlexGetConeSize(dm, point, &cconeSize);
1773: DMPlexGetCone(dm, point, &ccone);
1774: for (cc = 0; cc < cconeSize; ++cc) {
1775: PetscInt *closure = NULL;
1776: PetscInt closureSize, cl;
1778: DMLabelGetValue(label, ccone[cc], &val);
1779: if (val != -1) continue;
1780: DMPlexGetTransitiveClosure(dm, ccone[cc], PETSC_TRUE, &closureSize, &closure);
1781: for (cl = 0; cl < closureSize*2; cl += 2) {
1782: const PetscInt clp = closure[cl];
1784: DMLabelGetValue(label, clp, &val);
1785: if (val == -1) continue;
1786: DMLabelSetValue(label, ccone[cc], side*(shift+dim-1));
1787: break;
1788: }
1789: DMPlexRestoreTransitiveClosure(dm, ccone[cc], PETSC_TRUE, &closureSize, &closure);
1790: }
1791: again = 1;
1792: break;
1793: }
1794: }
1795: }
1796: }
1797: /* Classify the rest by cell membership */
1798: for (s = 0; s < starSize*2; s += 2) {
1799: const PetscInt point = star[s];
1801: DMLabelGetValue(label, point, &val);
1802: if (val == -1) {
1803: PetscInt *sstar = NULL;
1804: PetscInt sstarSize, ss;
1805: PetscBool marked = PETSC_FALSE;
1807: DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);
1808: for (ss = 0; ss < sstarSize*2; ss += 2) {
1809: const PetscInt spoint = sstar[ss];
1811: if ((spoint < cStart) || (spoint >= cMax)) continue;
1812: DMLabelGetValue(label, spoint, &val);
1813: if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
1814: DMLabelGetValue(depthLabel, point, &dep);
1815: if (val > 0) {
1816: DMLabelSetValue(label, point, shift+dep);
1817: } else {
1818: DMLabelSetValue(label, point, -(shift+dep));
1819: }
1820: marked = PETSC_TRUE;
1821: break;
1822: }
1823: DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);
1824: DMLabelGetValue(depthLabel, point, &dep);
1825: if (point < pMax[dep] && !marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
1826: }
1827: }
1828: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);
1829: }
1830: ISRestoreIndices(dimIS, &points);
1831: ISDestroy(&dimIS);
1832: /* If any faces touching the fault divide cells on either side, split them */
1833: DMLabelGetStratumIS(label, shift+dim-1, &facePosIS);
1834: DMLabelGetStratumIS(label, -(shift+dim-1), &faceNegIS);
1835: ISExpand(facePosIS, faceNegIS, &dimIS);
1836: ISDestroy(&facePosIS);
1837: ISDestroy(&faceNegIS);
1838: ISGetLocalSize(dimIS, &numPoints);
1839: ISGetIndices(dimIS, &points);
1840: for (p = 0; p < numPoints; ++p) {
1841: const PetscInt point = points[p];
1842: const PetscInt *support;
1843: PetscInt supportSize, valA, valB;
1845: DMPlexGetSupportSize(dm, point, &supportSize);
1846: if (supportSize != 2) continue;
1847: DMPlexGetSupport(dm, point, &support);
1848: DMLabelGetValue(label, support[0], &valA);
1849: DMLabelGetValue(label, support[1], &valB);
1850: if ((valA == -1) || (valB == -1)) continue;
1851: if (valA*valB > 0) continue;
1852: /* Split the face */
1853: DMLabelGetValue(label, point, &valA);
1854: DMLabelClearValue(label, point, valA);
1855: DMLabelSetValue(label, point, dim-1);
1856: /* Label its closure:
1857: unmarked: label as unsplit
1858: incident: relabel as split
1859: split: do nothing
1860: */
1861: {
1862: PetscInt *closure = NULL;
1863: PetscInt closureSize, cl;
1865: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1866: for (cl = 0; cl < closureSize*2; cl += 2) {
1867: DMLabelGetValue(label, closure[cl], &valA);
1868: if (valA == -1) { /* Mark as unsplit */
1869: DMLabelGetValue(depthLabel, closure[cl], &dep);
1870: DMLabelSetValue(label, closure[cl], shift2+dep);
1871: } else if (((valA >= shift) && (valA < shift2)) || ((valA <= -shift) && (valA > -shift2))) {
1872: DMLabelGetValue(depthLabel, closure[cl], &dep);
1873: DMLabelClearValue(label, closure[cl], valA);
1874: DMLabelSetValue(label, closure[cl], dep);
1875: }
1876: }
1877: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1878: }
1879: }
1880: ISRestoreIndices(dimIS, &points);
1881: ISDestroy(&dimIS);
1882: PetscFree(pMax);
1883: return(0);
1884: }
1888: /*@C
1889: DMPlexCreateHybridMesh - Create a mesh with hybrid cells along an internal interface
1891: Collective on dm
1893: Input Parameters:
1894: + dm - The original DM
1895: - labelName - The label specifying the interface vertices
1897: Output Parameters:
1898: + hybridLabel - The label fully marking the interface
1899: - dmHybrid - The new DM
1901: Level: developer
1903: .seealso: DMPlexConstructCohesiveCells(), DMPlexLabelCohesiveComplete(), DMCreate()
1904: @*/
1905: PetscErrorCode DMPlexCreateHybridMesh(DM dm, DMLabel label, DMLabel *hybridLabel, DM *dmHybrid)
1906: {
1907: DM idm;
1908: DMLabel subpointMap, hlabel;
1909: PetscInt dim;
1916: DMGetDimension(dm, &dim);
1917: DMPlexCreateSubmesh(dm, label, 1, &idm);
1918: DMPlexOrient(idm);
1919: DMPlexGetSubpointMap(idm, &subpointMap);
1920: DMLabelDuplicate(subpointMap, &hlabel);
1921: DMLabelClearStratum(hlabel, dim);
1922: DMPlexLabelCohesiveComplete(dm, hlabel, NULL, PETSC_FALSE, idm);
1923: DMDestroy(&idm);
1924: DMPlexConstructCohesiveCells(dm, hlabel, dmHybrid);
1925: if (hybridLabel) *hybridLabel = hlabel;
1926: else {DMLabelDestroy(&hlabel);}
1927: return(0);
1928: }
1932: /* Here we need the explicit assumption that:
1934: For any marked cell, the marked vertices constitute a single face
1935: */
1936: static PetscErrorCode DMPlexMarkSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, DM subdm)
1937: {
1938: IS subvertexIS = NULL;
1939: const PetscInt *subvertices;
1940: PetscInt *pStart, *pEnd, *pMax, pSize;
1941: PetscInt depth, dim, d, numSubVerticesInitial = 0, v;
1942: PetscErrorCode ierr;
1945: *numFaces = 0;
1946: *nFV = 0;
1947: DMPlexGetDepth(dm, &depth);
1948: DMGetDimension(dm, &dim);
1949: pSize = PetscMax(depth, dim) + 1;
1950: PetscMalloc3(pSize,&pStart,pSize,&pEnd,pSize,&pMax);
1951: DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
1952: for (d = 0; d <= depth; ++d) {
1953: DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);
1954: if (pMax[d] >= 0) pEnd[d] = PetscMin(pEnd[d], pMax[d]);
1955: }
1956: /* Loop over initial vertices and mark all faces in the collective star() */
1957: if (vertexLabel) {DMLabelGetStratumIS(vertexLabel, value, &subvertexIS);}
1958: if (subvertexIS) {
1959: ISGetSize(subvertexIS, &numSubVerticesInitial);
1960: ISGetIndices(subvertexIS, &subvertices);
1961: }
1962: for (v = 0; v < numSubVerticesInitial; ++v) {
1963: const PetscInt vertex = subvertices[v];
1964: PetscInt *star = NULL;
1965: PetscInt starSize, s, numCells = 0, c;
1967: DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
1968: for (s = 0; s < starSize*2; s += 2) {
1969: const PetscInt point = star[s];
1970: if ((point >= pStart[depth]) && (point < pEnd[depth])) star[numCells++] = point;
1971: }
1972: for (c = 0; c < numCells; ++c) {
1973: const PetscInt cell = star[c];
1974: PetscInt *closure = NULL;
1975: PetscInt closureSize, cl;
1976: PetscInt cellLoc, numCorners = 0, faceSize = 0;
1978: DMLabelGetValue(subpointMap, cell, &cellLoc);
1979: if (cellLoc == 2) continue;
1980: if (cellLoc >= 0) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d has dimension %d in the surface label", cell, cellLoc);
1981: DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
1982: for (cl = 0; cl < closureSize*2; cl += 2) {
1983: const PetscInt point = closure[cl];
1984: PetscInt vertexLoc;
1986: if ((point >= pStart[0]) && (point < pEnd[0])) {
1987: ++numCorners;
1988: DMLabelGetValue(vertexLabel, point, &vertexLoc);
1989: if (vertexLoc == value) closure[faceSize++] = point;
1990: }
1991: }
1992: if (!(*nFV)) {DMPlexGetNumFaceVertices(dm, dim, numCorners, nFV);}
1993: if (faceSize > *nFV) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
1994: if (faceSize == *nFV) {
1995: const PetscInt *cells = NULL;
1996: PetscInt numCells, nc;
1998: ++(*numFaces);
1999: for (cl = 0; cl < faceSize; ++cl) {
2000: DMLabelSetValue(subpointMap, closure[cl], 0);
2001: }
2002: DMPlexGetJoin(dm, faceSize, closure, &numCells, &cells);
2003: for (nc = 0; nc < numCells; ++nc) {
2004: DMLabelSetValue(subpointMap, cells[nc], 2);
2005: }
2006: DMPlexRestoreJoin(dm, faceSize, closure, &numCells, &cells);
2007: }
2008: DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
2009: }
2010: DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
2011: }
2012: if (subvertexIS) {
2013: ISRestoreIndices(subvertexIS, &subvertices);
2014: }
2015: ISDestroy(&subvertexIS);
2016: PetscFree3(pStart,pEnd,pMax);
2017: return(0);
2018: }
2022: static PetscErrorCode DMPlexMarkSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, DM subdm)
2023: {
2024: IS subvertexIS = NULL;
2025: const PetscInt *subvertices;
2026: PetscInt *pStart, *pEnd, *pMax;
2027: PetscInt dim, d, numSubVerticesInitial = 0, v;
2028: PetscErrorCode ierr;
2031: DMGetDimension(dm, &dim);
2032: PetscMalloc3(dim+1,&pStart,dim+1,&pEnd,dim+1,&pMax);
2033: DMPlexGetHybridBounds(dm, &pMax[dim], dim>1 ? &pMax[dim-1] : NULL, dim > 2 ? &pMax[1] : NULL, &pMax[0]);
2034: for (d = 0; d <= dim; ++d) {
2035: DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);
2036: if (pMax[d] >= 0) pEnd[d] = PetscMin(pEnd[d], pMax[d]);
2037: }
2038: /* Loop over initial vertices and mark all faces in the collective star() */
2039: if (vertexLabel) {
2040: DMLabelGetStratumIS(vertexLabel, value, &subvertexIS);
2041: if (subvertexIS) {
2042: ISGetSize(subvertexIS, &numSubVerticesInitial);
2043: ISGetIndices(subvertexIS, &subvertices);
2044: }
2045: }
2046: for (v = 0; v < numSubVerticesInitial; ++v) {
2047: const PetscInt vertex = subvertices[v];
2048: PetscInt *star = NULL;
2049: PetscInt starSize, s, numFaces = 0, f;
2051: DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
2052: for (s = 0; s < starSize*2; s += 2) {
2053: const PetscInt point = star[s];
2054: if ((point >= pStart[dim-1]) && (point < pEnd[dim-1])) star[numFaces++] = point;
2055: }
2056: for (f = 0; f < numFaces; ++f) {
2057: const PetscInt face = star[f];
2058: PetscInt *closure = NULL;
2059: PetscInt closureSize, c;
2060: PetscInt faceLoc;
2062: DMLabelGetValue(subpointMap, face, &faceLoc);
2063: if (faceLoc == dim-1) continue;
2064: if (faceLoc >= 0) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc);
2065: DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);
2066: for (c = 0; c < closureSize*2; c += 2) {
2067: const PetscInt point = closure[c];
2068: PetscInt vertexLoc;
2070: if ((point >= pStart[0]) && (point < pEnd[0])) {
2071: DMLabelGetValue(vertexLabel, point, &vertexLoc);
2072: if (vertexLoc != value) break;
2073: }
2074: }
2075: if (c == closureSize*2) {
2076: const PetscInt *support;
2077: PetscInt supportSize, s;
2079: for (c = 0; c < closureSize*2; c += 2) {
2080: const PetscInt point = closure[c];
2082: for (d = 0; d < dim; ++d) {
2083: if ((point >= pStart[d]) && (point < pEnd[d])) {
2084: DMLabelSetValue(subpointMap, point, d);
2085: break;
2086: }
2087: }
2088: }
2089: DMPlexGetSupportSize(dm, face, &supportSize);
2090: DMPlexGetSupport(dm, face, &support);
2091: for (s = 0; s < supportSize; ++s) {
2092: DMLabelSetValue(subpointMap, support[s], dim);
2093: }
2094: }
2095: DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);
2096: }
2097: DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
2098: }
2099: if (subvertexIS) {ISRestoreIndices(subvertexIS, &subvertices);}
2100: ISDestroy(&subvertexIS);
2101: PetscFree3(pStart,pEnd,pMax);
2102: return(0);
2103: }
2107: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char labelname[], PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, PetscInt *subCells[], DM subdm)
2108: {
2109: DMLabel label = NULL;
2110: const PetscInt *cone;
2111: PetscInt dim, cMax, cEnd, c, subc = 0, p, coneSize = -1;
2112: PetscErrorCode ierr;
2115: *numFaces = 0;
2116: *nFV = 0;
2117: if (labelname) {DMGetLabel(dm, labelname, &label);}
2118: *subCells = NULL;
2119: DMGetDimension(dm, &dim);
2120: DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
2121: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
2122: if (cMax < 0) return(0);
2123: if (label) {
2124: for (c = cMax; c < cEnd; ++c) {
2125: PetscInt val;
2127: DMLabelGetValue(label, c, &val);
2128: if (val == value) {
2129: ++(*numFaces);
2130: DMPlexGetConeSize(dm, c, &coneSize);
2131: }
2132: }
2133: } else {
2134: *numFaces = cEnd - cMax;
2135: DMPlexGetConeSize(dm, cMax, &coneSize);
2136: }
2137: PetscMalloc1(*numFaces *2, subCells);
2138: if (!(*numFaces)) return(0);
2139: *nFV = hasLagrange ? coneSize/3 : coneSize/2;
2140: for (c = cMax; c < cEnd; ++c) {
2141: const PetscInt *cells;
2142: PetscInt numCells;
2144: if (label) {
2145: PetscInt val;
2147: DMLabelGetValue(label, c, &val);
2148: if (val != value) continue;
2149: }
2150: DMPlexGetCone(dm, c, &cone);
2151: for (p = 0; p < *nFV; ++p) {
2152: DMLabelSetValue(subpointMap, cone[p], 0);
2153: }
2154: /* Negative face */
2155: DMPlexGetJoin(dm, *nFV, cone, &numCells, &cells);
2156: /* Not true in parallel
2157: if (numCells != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
2158: for (p = 0; p < numCells; ++p) {
2159: DMLabelSetValue(subpointMap, cells[p], 2);
2160: (*subCells)[subc++] = cells[p];
2161: }
2162: DMPlexRestoreJoin(dm, *nFV, cone, &numCells, &cells);
2163: /* Positive face is not included */
2164: }
2165: return(0);
2166: }
2170: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Interpolated(DM dm, DMLabel label, PetscInt value, DMLabel subpointMap, DM subdm)
2171: {
2172: PetscInt *pStart, *pEnd;
2173: PetscInt dim, cMax, cEnd, c, d;
2177: DMGetDimension(dm, &dim);
2178: DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
2179: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
2180: if (cMax < 0) return(0);
2181: PetscMalloc2(dim+1,&pStart,dim+1,&pEnd);
2182: for (d = 0; d <= dim; ++d) {DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);}
2183: for (c = cMax; c < cEnd; ++c) {
2184: const PetscInt *cone;
2185: PetscInt *closure = NULL;
2186: PetscInt fconeSize, coneSize, closureSize, cl, val;
2188: if (label) {
2189: DMLabelGetValue(label, c, &val);
2190: if (val != value) continue;
2191: }
2192: DMPlexGetConeSize(dm, c, &coneSize);
2193: DMPlexGetCone(dm, c, &cone);
2194: DMPlexGetConeSize(dm, cone[0], &fconeSize);
2195: if (coneSize != (fconeSize ? fconeSize : 1) + 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells");
2196: /* Negative face */
2197: DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure);
2198: for (cl = 0; cl < closureSize*2; cl += 2) {
2199: const PetscInt point = closure[cl];
2201: for (d = 0; d <= dim; ++d) {
2202: if ((point >= pStart[d]) && (point < pEnd[d])) {
2203: DMLabelSetValue(subpointMap, point, d);
2204: break;
2205: }
2206: }
2207: }
2208: DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure);
2209: /* Cells -- positive face is not included */
2210: for (cl = 0; cl < 1; ++cl) {
2211: const PetscInt *support;
2212: PetscInt supportSize, s;
2214: DMPlexGetSupportSize(dm, cone[cl], &supportSize);
2215: /* if (supportSize != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive faces should separate two cells"); */
2216: DMPlexGetSupport(dm, cone[cl], &support);
2217: for (s = 0; s < supportSize; ++s) {
2218: DMLabelSetValue(subpointMap, support[s], dim);
2219: }
2220: }
2221: }
2222: PetscFree2(pStart, pEnd);
2223: return(0);
2224: }
2228: PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2229: {
2230: MPI_Comm comm;
2231: PetscBool posOrient = PETSC_FALSE;
2232: const PetscInt debug = 0;
2233: PetscInt cellDim, faceSize, f;
2237: PetscObjectGetComm((PetscObject)dm,&comm);
2238: DMGetDimension(dm, &cellDim);
2239: if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);}
2241: if (cellDim == 1 && numCorners == 2) {
2242: /* Triangle */
2243: faceSize = numCorners-1;
2244: posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
2245: } else if (cellDim == 2 && numCorners == 3) {
2246: /* Triangle */
2247: faceSize = numCorners-1;
2248: posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
2249: } else if (cellDim == 3 && numCorners == 4) {
2250: /* Tetrahedron */
2251: faceSize = numCorners-1;
2252: posOrient = (oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
2253: } else if (cellDim == 1 && numCorners == 3) {
2254: /* Quadratic line */
2255: faceSize = 1;
2256: posOrient = PETSC_TRUE;
2257: } else if (cellDim == 2 && numCorners == 4) {
2258: /* Quads */
2259: faceSize = 2;
2260: if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
2261: posOrient = PETSC_TRUE;
2262: } else if ((indices[0] == 3) && (indices[1] == 0)) {
2263: posOrient = PETSC_TRUE;
2264: } else {
2265: if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
2266: posOrient = PETSC_FALSE;
2267: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
2268: }
2269: } else if (cellDim == 2 && numCorners == 6) {
2270: /* Quadratic triangle (I hate this) */
2271: /* Edges are determined by the first 2 vertices (corners of edges) */
2272: const PetscInt faceSizeTri = 3;
2273: PetscInt sortedIndices[3], i, iFace;
2274: PetscBool found = PETSC_FALSE;
2275: PetscInt faceVerticesTriSorted[9] = {
2276: 0, 3, 4, /* bottom */
2277: 1, 4, 5, /* right */
2278: 2, 3, 5, /* left */
2279: };
2280: PetscInt faceVerticesTri[9] = {
2281: 0, 3, 4, /* bottom */
2282: 1, 4, 5, /* right */
2283: 2, 5, 3, /* left */
2284: };
2286: for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
2287: PetscSortInt(faceSizeTri, sortedIndices);
2288: for (iFace = 0; iFace < 3; ++iFace) {
2289: const PetscInt ii = iFace*faceSizeTri;
2290: PetscInt fVertex, cVertex;
2292: if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
2293: (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
2294: for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
2295: for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
2296: if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
2297: faceVertices[fVertex] = origVertices[cVertex];
2298: break;
2299: }
2300: }
2301: }
2302: found = PETSC_TRUE;
2303: break;
2304: }
2305: }
2306: if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
2307: if (posOriented) *posOriented = PETSC_TRUE;
2308: return(0);
2309: } else if (cellDim == 2 && numCorners == 9) {
2310: /* Quadratic quad (I hate this) */
2311: /* Edges are determined by the first 2 vertices (corners of edges) */
2312: const PetscInt faceSizeQuad = 3;
2313: PetscInt sortedIndices[3], i, iFace;
2314: PetscBool found = PETSC_FALSE;
2315: PetscInt faceVerticesQuadSorted[12] = {
2316: 0, 1, 4, /* bottom */
2317: 1, 2, 5, /* right */
2318: 2, 3, 6, /* top */
2319: 0, 3, 7, /* left */
2320: };
2321: PetscInt faceVerticesQuad[12] = {
2322: 0, 1, 4, /* bottom */
2323: 1, 2, 5, /* right */
2324: 2, 3, 6, /* top */
2325: 3, 0, 7, /* left */
2326: };
2328: for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
2329: PetscSortInt(faceSizeQuad, sortedIndices);
2330: for (iFace = 0; iFace < 4; ++iFace) {
2331: const PetscInt ii = iFace*faceSizeQuad;
2332: PetscInt fVertex, cVertex;
2334: if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
2335: (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
2336: for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
2337: for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
2338: if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
2339: faceVertices[fVertex] = origVertices[cVertex];
2340: break;
2341: }
2342: }
2343: }
2344: found = PETSC_TRUE;
2345: break;
2346: }
2347: }
2348: if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
2349: if (posOriented) *posOriented = PETSC_TRUE;
2350: return(0);
2351: } else if (cellDim == 3 && numCorners == 8) {
2352: /* Hexes
2353: A hex is two oriented quads with the normal of the first
2354: pointing up at the second.
2356: 7---6
2357: /| /|
2358: 4---5 |
2359: | 1-|-2
2360: |/ |/
2361: 0---3
2363: Faces are determined by the first 4 vertices (corners of faces) */
2364: const PetscInt faceSizeHex = 4;
2365: PetscInt sortedIndices[4], i, iFace;
2366: PetscBool found = PETSC_FALSE;
2367: PetscInt faceVerticesHexSorted[24] = {
2368: 0, 1, 2, 3, /* bottom */
2369: 4, 5, 6, 7, /* top */
2370: 0, 3, 4, 5, /* front */
2371: 2, 3, 5, 6, /* right */
2372: 1, 2, 6, 7, /* back */
2373: 0, 1, 4, 7, /* left */
2374: };
2375: PetscInt faceVerticesHex[24] = {
2376: 1, 2, 3, 0, /* bottom */
2377: 4, 5, 6, 7, /* top */
2378: 0, 3, 5, 4, /* front */
2379: 3, 2, 6, 5, /* right */
2380: 2, 1, 7, 6, /* back */
2381: 1, 0, 4, 7, /* left */
2382: };
2384: for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
2385: PetscSortInt(faceSizeHex, sortedIndices);
2386: for (iFace = 0; iFace < 6; ++iFace) {
2387: const PetscInt ii = iFace*faceSizeHex;
2388: PetscInt fVertex, cVertex;
2390: if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
2391: (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
2392: (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
2393: (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
2394: for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
2395: for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
2396: if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
2397: faceVertices[fVertex] = origVertices[cVertex];
2398: break;
2399: }
2400: }
2401: }
2402: found = PETSC_TRUE;
2403: break;
2404: }
2405: }
2406: if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2407: if (posOriented) *posOriented = PETSC_TRUE;
2408: return(0);
2409: } else if (cellDim == 3 && numCorners == 10) {
2410: /* Quadratic tet */
2411: /* Faces are determined by the first 3 vertices (corners of faces) */
2412: const PetscInt faceSizeTet = 6;
2413: PetscInt sortedIndices[6], i, iFace;
2414: PetscBool found = PETSC_FALSE;
2415: PetscInt faceVerticesTetSorted[24] = {
2416: 0, 1, 2, 6, 7, 8, /* bottom */
2417: 0, 3, 4, 6, 7, 9, /* front */
2418: 1, 4, 5, 7, 8, 9, /* right */
2419: 2, 3, 5, 6, 8, 9, /* left */
2420: };
2421: PetscInt faceVerticesTet[24] = {
2422: 0, 1, 2, 6, 7, 8, /* bottom */
2423: 0, 4, 3, 6, 7, 9, /* front */
2424: 1, 5, 4, 7, 8, 9, /* right */
2425: 2, 3, 5, 8, 6, 9, /* left */
2426: };
2428: for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
2429: PetscSortInt(faceSizeTet, sortedIndices);
2430: for (iFace=0; iFace < 4; ++iFace) {
2431: const PetscInt ii = iFace*faceSizeTet;
2432: PetscInt fVertex, cVertex;
2434: if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
2435: (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
2436: (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
2437: (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
2438: for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
2439: for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
2440: if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
2441: faceVertices[fVertex] = origVertices[cVertex];
2442: break;
2443: }
2444: }
2445: }
2446: found = PETSC_TRUE;
2447: break;
2448: }
2449: }
2450: if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
2451: if (posOriented) *posOriented = PETSC_TRUE;
2452: return(0);
2453: } else if (cellDim == 3 && numCorners == 27) {
2454: /* Quadratic hexes (I hate this)
2455: A hex is two oriented quads with the normal of the first
2456: pointing up at the second.
2458: 7---6
2459: /| /|
2460: 4---5 |
2461: | 3-|-2
2462: |/ |/
2463: 0---1
2465: Faces are determined by the first 4 vertices (corners of faces) */
2466: const PetscInt faceSizeQuadHex = 9;
2467: PetscInt sortedIndices[9], i, iFace;
2468: PetscBool found = PETSC_FALSE;
2469: PetscInt faceVerticesQuadHexSorted[54] = {
2470: 0, 1, 2, 3, 8, 9, 10, 11, 24, /* bottom */
2471: 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */
2472: 0, 1, 4, 5, 8, 12, 16, 17, 22, /* front */
2473: 1, 2, 5, 6, 9, 13, 17, 18, 21, /* right */
2474: 2, 3, 6, 7, 10, 14, 18, 19, 23, /* back */
2475: 0, 3, 4, 7, 11, 15, 16, 19, 20, /* left */
2476: };
2477: PetscInt faceVerticesQuadHex[54] = {
2478: 3, 2, 1, 0, 10, 9, 8, 11, 24, /* bottom */
2479: 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */
2480: 0, 1, 5, 4, 8, 17, 12, 16, 22, /* front */
2481: 1, 2, 6, 5, 9, 18, 13, 17, 21, /* right */
2482: 2, 3, 7, 6, 10, 19, 14, 18, 23, /* back */
2483: 3, 0, 4, 7, 11, 16, 15, 19, 20 /* left */
2484: };
2486: for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
2487: PetscSortInt(faceSizeQuadHex, sortedIndices);
2488: for (iFace = 0; iFace < 6; ++iFace) {
2489: const PetscInt ii = iFace*faceSizeQuadHex;
2490: PetscInt fVertex, cVertex;
2492: if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
2493: (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
2494: (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
2495: (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
2496: for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
2497: for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
2498: if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
2499: faceVertices[fVertex] = origVertices[cVertex];
2500: break;
2501: }
2502: }
2503: }
2504: found = PETSC_TRUE;
2505: break;
2506: }
2507: }
2508: if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2509: if (posOriented) *posOriented = PETSC_TRUE;
2510: return(0);
2511: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
2512: if (!posOrient) {
2513: if (debug) {PetscPrintf(comm, " Reversing initial face orientation\n");}
2514: for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
2515: } else {
2516: if (debug) {PetscPrintf(comm, " Keeping initial face orientation\n");}
2517: for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
2518: }
2519: if (posOriented) *posOriented = posOrient;
2520: return(0);
2521: }
2525: /*
2526: Given a cell and a face, as a set of vertices,
2527: return the oriented face, as a set of vertices, in faceVertices
2528: The orientation is such that the face normal points out of the cell
2529: */
2530: PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2531: {
2532: const PetscInt *cone = NULL;
2533: PetscInt coneSize, v, f, v2;
2534: PetscInt oppositeVertex = -1;
2535: PetscErrorCode ierr;
2538: DMPlexGetConeSize(dm, cell, &coneSize);
2539: DMPlexGetCone(dm, cell, &cone);
2540: for (v = 0, v2 = 0; v < coneSize; ++v) {
2541: PetscBool found = PETSC_FALSE;
2543: for (f = 0; f < faceSize; ++f) {
2544: if (face[f] == cone[v]) {
2545: found = PETSC_TRUE; break;
2546: }
2547: }
2548: if (found) {
2549: indices[v2] = v;
2550: origVertices[v2] = cone[v];
2551: ++v2;
2552: } else {
2553: oppositeVertex = v;
2554: }
2555: }
2556: DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);
2557: return(0);
2558: }
2562: /*
2563: DMPlexInsertFace_Internal - Puts a face into the mesh
2565: Not collective
2567: Input Parameters:
2568: + dm - The DMPlex
2569: . numFaceVertex - The number of vertices in the face
2570: . faceVertices - The vertices in the face for dm
2571: . subfaceVertices - The vertices in the face for subdm
2572: . numCorners - The number of vertices in the cell
2573: . cell - A cell in dm containing the face
2574: . subcell - A cell in subdm containing the face
2575: . firstFace - First face in the mesh
2576: - newFacePoint - Next face in the mesh
2578: Output Parameters:
2579: . newFacePoint - Contains next face point number on input, updated on output
2581: Level: developer
2582: */
2583: 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)
2584: {
2585: MPI_Comm comm;
2586: DM_Plex *submesh = (DM_Plex*) subdm->data;
2587: const PetscInt *faces;
2588: PetscInt numFaces, coneSize;
2589: PetscErrorCode ierr;
2592: PetscObjectGetComm((PetscObject)dm,&comm);
2593: DMPlexGetConeSize(subdm, subcell, &coneSize);
2594: if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
2595: #if 0
2596: /* Cannot use this because support() has not been constructed yet */
2597: DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);
2598: #else
2599: {
2600: PetscInt f;
2602: numFaces = 0;
2603: DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);
2604: for (f = firstFace; f < *newFacePoint; ++f) {
2605: PetscInt dof, off, d;
2607: PetscSectionGetDof(submesh->coneSection, f, &dof);
2608: PetscSectionGetOffset(submesh->coneSection, f, &off);
2609: /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
2610: for (d = 0; d < dof; ++d) {
2611: const PetscInt p = submesh->cones[off+d];
2612: PetscInt v;
2614: for (v = 0; v < numFaceVertices; ++v) {
2615: if (subfaceVertices[v] == p) break;
2616: }
2617: if (v == numFaceVertices) break;
2618: }
2619: if (d == dof) {
2620: numFaces = 1;
2621: ((PetscInt*) faces)[0] = f;
2622: }
2623: }
2624: }
2625: #endif
2626: if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
2627: else if (numFaces == 1) {
2628: /* Add the other cell neighbor for this face */
2629: DMPlexSetCone(subdm, subcell, faces);
2630: } else {
2631: PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
2632: PetscBool posOriented;
2634: DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);
2635: origVertices = &orientedVertices[numFaceVertices];
2636: indices = &orientedVertices[numFaceVertices*2];
2637: orientedSubVertices = &orientedVertices[numFaceVertices*3];
2638: DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);
2639: /* TODO: I know that routine should return a permutation, not the indices */
2640: for (v = 0; v < numFaceVertices; ++v) {
2641: const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
2642: for (ov = 0; ov < numFaceVertices; ++ov) {
2643: if (orientedVertices[ov] == vertex) {
2644: orientedSubVertices[ov] = subvertex;
2645: break;
2646: }
2647: }
2648: if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
2649: }
2650: DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);
2651: DMPlexSetCone(subdm, subcell, newFacePoint);
2652: DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);
2653: ++(*newFacePoint);
2654: }
2655: #if 0
2656: DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);
2657: #else
2658: DMRestoreWorkArray(subdm, 1, PETSC_INT, (void **) &faces);
2659: #endif
2660: return(0);
2661: }
2665: static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm)
2666: {
2667: MPI_Comm comm;
2668: DMLabel subpointMap;
2669: IS subvertexIS, subcellIS;
2670: const PetscInt *subVertices, *subCells;
2671: PetscInt numSubVertices, firstSubVertex, numSubCells;
2672: PetscInt *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0;
2673: PetscInt vStart, vEnd, c, f;
2674: PetscErrorCode ierr;
2677: PetscObjectGetComm((PetscObject)dm,&comm);
2678: /* Create subpointMap which marks the submesh */
2679: DMLabelCreate("subpoint_map", &subpointMap);
2680: DMPlexSetSubpointMap(subdm, subpointMap);
2681: DMLabelDestroy(&subpointMap);
2682: if (vertexLabel) {DMPlexMarkSubmesh_Uninterpolated(dm, vertexLabel, value, subpointMap, &numSubFaces, &nFV, subdm);}
2683: /* Setup chart */
2684: DMLabelGetStratumSize(subpointMap, 0, &numSubVertices);
2685: DMLabelGetStratumSize(subpointMap, 2, &numSubCells);
2686: DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVertices);
2687: DMPlexSetVTKCellHeight(subdm, 1);
2688: /* Set cone sizes */
2689: firstSubVertex = numSubCells;
2690: firstSubFace = numSubCells+numSubVertices;
2691: newFacePoint = firstSubFace;
2692: DMLabelGetStratumIS(subpointMap, 0, &subvertexIS);
2693: if (subvertexIS) {ISGetIndices(subvertexIS, &subVertices);}
2694: DMLabelGetStratumIS(subpointMap, 2, &subcellIS);
2695: if (subcellIS) {ISGetIndices(subcellIS, &subCells);}
2696: for (c = 0; c < numSubCells; ++c) {
2697: DMPlexSetConeSize(subdm, c, 1);
2698: }
2699: for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
2700: DMPlexSetConeSize(subdm, f, nFV);
2701: }
2702: DMSetUp(subdm);
2703: /* Create face cones */
2704: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
2705: DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2706: DMGetWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
2707: for (c = 0; c < numSubCells; ++c) {
2708: const PetscInt cell = subCells[c];
2709: const PetscInt subcell = c;
2710: PetscInt *closure = NULL;
2711: PetscInt closureSize, cl, numCorners = 0, faceSize = 0;
2713: DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
2714: for (cl = 0; cl < closureSize*2; cl += 2) {
2715: const PetscInt point = closure[cl];
2716: PetscInt subVertex;
2718: if ((point >= vStart) && (point < vEnd)) {
2719: ++numCorners;
2720: PetscFindInt(point, numSubVertices, subVertices, &subVertex);
2721: if (subVertex >= 0) {
2722: closure[faceSize] = point;
2723: subface[faceSize] = firstSubVertex+subVertex;
2724: ++faceSize;
2725: }
2726: }
2727: }
2728: if (faceSize > nFV) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
2729: if (faceSize == nFV) {
2730: DMPlexInsertFace_Internal(dm, subdm, faceSize, closure, subface, numCorners, cell, subcell, firstSubFace, &newFacePoint);
2731: }
2732: DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
2733: }
2734: DMRestoreWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
2735: DMPlexSymmetrize(subdm);
2736: DMPlexStratify(subdm);
2737: /* Build coordinates */
2738: {
2739: PetscSection coordSection, subCoordSection;
2740: Vec coordinates, subCoordinates;
2741: PetscScalar *coords, *subCoords;
2742: PetscInt numComp, coordSize, v;
2743: const char *name;
2745: DMGetCoordinateSection(dm, &coordSection);
2746: DMGetCoordinatesLocal(dm, &coordinates);
2747: DMGetCoordinateSection(subdm, &subCoordSection);
2748: PetscSectionSetNumFields(subCoordSection, 1);
2749: PetscSectionGetFieldComponents(coordSection, 0, &numComp);
2750: PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
2751: PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);
2752: for (v = 0; v < numSubVertices; ++v) {
2753: const PetscInt vertex = subVertices[v];
2754: const PetscInt subvertex = firstSubVertex+v;
2755: PetscInt dof;
2757: PetscSectionGetDof(coordSection, vertex, &dof);
2758: PetscSectionSetDof(subCoordSection, subvertex, dof);
2759: PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
2760: }
2761: PetscSectionSetUp(subCoordSection);
2762: PetscSectionGetStorageSize(subCoordSection, &coordSize);
2763: VecCreate(PETSC_COMM_SELF, &subCoordinates);
2764: PetscObjectGetName((PetscObject)coordinates,&name);
2765: PetscObjectSetName((PetscObject)subCoordinates,name);
2766: VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
2767: VecSetType(subCoordinates,VECSTANDARD);
2768: if (coordSize) {
2769: VecGetArray(coordinates, &coords);
2770: VecGetArray(subCoordinates, &subCoords);
2771: for (v = 0; v < numSubVertices; ++v) {
2772: const PetscInt vertex = subVertices[v];
2773: const PetscInt subvertex = firstSubVertex+v;
2774: PetscInt dof, off, sdof, soff, d;
2776: PetscSectionGetDof(coordSection, vertex, &dof);
2777: PetscSectionGetOffset(coordSection, vertex, &off);
2778: PetscSectionGetDof(subCoordSection, subvertex, &sdof);
2779: PetscSectionGetOffset(subCoordSection, subvertex, &soff);
2780: if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
2781: for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
2782: }
2783: VecRestoreArray(coordinates, &coords);
2784: VecRestoreArray(subCoordinates, &subCoords);
2785: }
2786: DMSetCoordinatesLocal(subdm, subCoordinates);
2787: VecDestroy(&subCoordinates);
2788: }
2789: /* Cleanup */
2790: if (subvertexIS) {ISRestoreIndices(subvertexIS, &subVertices);}
2791: ISDestroy(&subvertexIS);
2792: if (subcellIS) {ISRestoreIndices(subcellIS, &subCells);}
2793: ISDestroy(&subcellIS);
2794: return(0);
2795: }
2799: PETSC_STATIC_INLINE PetscInt DMPlexFilterPoint_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[])
2800: {
2801: PetscInt subPoint;
2804: PetscFindInt(point, numSubPoints, subPoints, &subPoint); if (ierr < 0) return ierr;
2805: return subPoint < 0 ? subPoint : firstSubPoint+subPoint;
2806: }
2810: static PetscErrorCode DMPlexCreateSubmeshGeneric_Interpolated(DM dm, DMLabel label, PetscInt value, PetscBool isCohesive, PetscInt cellHeight, DM subdm)
2811: {
2812: MPI_Comm comm;
2813: DMLabel subpointMap;
2814: IS *subpointIS;
2815: const PetscInt **subpoints;
2816: PetscInt *numSubPoints, *firstSubPoint, *coneNew, *orntNew;
2817: PetscInt totSubPoints = 0, maxConeSize, dim, p, d, v;
2818: PetscErrorCode ierr;
2821: PetscObjectGetComm((PetscObject)dm,&comm);
2822: /* Create subpointMap which marks the submesh */
2823: DMLabelCreate("subpoint_map", &subpointMap);
2824: DMPlexSetSubpointMap(subdm, subpointMap);
2825: if (cellHeight) {
2826: if (isCohesive) {DMPlexMarkCohesiveSubmesh_Interpolated(dm, label, value, subpointMap, subdm);}
2827: else {DMPlexMarkSubmesh_Interpolated(dm, label, value, subpointMap, subdm);}
2828: } else {
2829: DMLabel depth;
2830: IS pointIS;
2831: const PetscInt *points;
2832: PetscInt numPoints;
2834: DMPlexGetDepthLabel(dm, &depth);
2835: DMLabelGetStratumSize(label, value, &numPoints);
2836: DMLabelGetStratumIS(label, value, &pointIS);
2837: ISGetIndices(pointIS, &points);
2838: for (p = 0; p < numPoints; ++p) {
2839: PetscInt *closure = NULL;
2840: PetscInt closureSize, c, pdim;
2842: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);
2843: for (c = 0; c < closureSize*2; c += 2) {
2844: DMLabelGetValue(depth, closure[c], &pdim);
2845: DMLabelSetValue(subpointMap, closure[c], pdim);
2846: }
2847: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);
2848: }
2849: ISRestoreIndices(pointIS, &points);
2850: ISDestroy(&pointIS);
2851: }
2852: DMLabelDestroy(&subpointMap);
2853: /* Setup chart */
2854: DMGetDimension(dm, &dim);
2855: PetscMalloc4(dim+1,&numSubPoints,dim+1,&firstSubPoint,dim+1,&subpointIS,dim+1,&subpoints);
2856: for (d = 0; d <= dim; ++d) {
2857: DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d]);
2858: totSubPoints += numSubPoints[d];
2859: }
2860: DMPlexSetChart(subdm, 0, totSubPoints);
2861: DMPlexSetVTKCellHeight(subdm, cellHeight);
2862: /* Set cone sizes */
2863: firstSubPoint[dim] = 0;
2864: firstSubPoint[0] = firstSubPoint[dim] + numSubPoints[dim];
2865: if (dim > 1) {firstSubPoint[dim-1] = firstSubPoint[0] + numSubPoints[0];}
2866: if (dim > 2) {firstSubPoint[dim-2] = firstSubPoint[dim-1] + numSubPoints[dim-1];}
2867: for (d = 0; d <= dim; ++d) {
2868: DMLabelGetStratumIS(subpointMap, d, &subpointIS[d]);
2869: if (subpointIS[d]) {ISGetIndices(subpointIS[d], &subpoints[d]);}
2870: }
2871: for (d = 0; d <= dim; ++d) {
2872: for (p = 0; p < numSubPoints[d]; ++p) {
2873: const PetscInt point = subpoints[d][p];
2874: const PetscInt subpoint = firstSubPoint[d] + p;
2875: const PetscInt *cone;
2876: PetscInt coneSize, coneSizeNew, c, val;
2878: DMPlexGetConeSize(dm, point, &coneSize);
2879: DMPlexSetConeSize(subdm, subpoint, coneSize);
2880: if (cellHeight && (d == dim)) {
2881: DMPlexGetCone(dm, point, &cone);
2882: for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
2883: DMLabelGetValue(subpointMap, cone[c], &val);
2884: if (val >= 0) coneSizeNew++;
2885: }
2886: DMPlexSetConeSize(subdm, subpoint, coneSizeNew);
2887: }
2888: }
2889: }
2890: DMSetUp(subdm);
2891: /* Set cones */
2892: DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2893: PetscMalloc2(maxConeSize,&coneNew,maxConeSize,&orntNew);
2894: for (d = 0; d <= dim; ++d) {
2895: for (p = 0; p < numSubPoints[d]; ++p) {
2896: const PetscInt point = subpoints[d][p];
2897: const PetscInt subpoint = firstSubPoint[d] + p;
2898: const PetscInt *cone, *ornt;
2899: PetscInt coneSize, subconeSize, coneSizeNew, c, subc;
2901: DMPlexGetConeSize(dm, point, &coneSize);
2902: DMPlexGetConeSize(subdm, subpoint, &subconeSize);
2903: DMPlexGetCone(dm, point, &cone);
2904: DMPlexGetConeOrientation(dm, point, &ornt);
2905: for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
2906: PetscFindInt(cone[c], numSubPoints[d-1], subpoints[d-1], &subc);
2907: if (subc >= 0) {
2908: coneNew[coneSizeNew] = firstSubPoint[d-1] + subc;
2909: orntNew[coneSizeNew] = ornt[c];
2910: ++coneSizeNew;
2911: }
2912: }
2913: if (coneSizeNew != subconeSize) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of cone points located %d does not match subcone size %d", coneSizeNew, subconeSize);
2914: DMPlexSetCone(subdm, subpoint, coneNew);
2915: DMPlexSetConeOrientation(subdm, subpoint, orntNew);
2916: }
2917: }
2918: PetscFree2(coneNew,orntNew);
2919: DMPlexSymmetrize(subdm);
2920: DMPlexStratify(subdm);
2921: /* Build coordinates */
2922: {
2923: PetscSection coordSection, subCoordSection;
2924: Vec coordinates, subCoordinates;
2925: PetscScalar *coords, *subCoords;
2926: PetscInt numComp, coordSize;
2927: const char *name;
2929: DMGetCoordinateSection(dm, &coordSection);
2930: DMGetCoordinatesLocal(dm, &coordinates);
2931: DMGetCoordinateSection(subdm, &subCoordSection);
2932: PetscSectionSetNumFields(subCoordSection, 1);
2933: PetscSectionGetFieldComponents(coordSection, 0, &numComp);
2934: PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
2935: PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0]+numSubPoints[0]);
2936: for (v = 0; v < numSubPoints[0]; ++v) {
2937: const PetscInt vertex = subpoints[0][v];
2938: const PetscInt subvertex = firstSubPoint[0]+v;
2939: PetscInt dof;
2941: PetscSectionGetDof(coordSection, vertex, &dof);
2942: PetscSectionSetDof(subCoordSection, subvertex, dof);
2943: PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
2944: }
2945: PetscSectionSetUp(subCoordSection);
2946: PetscSectionGetStorageSize(subCoordSection, &coordSize);
2947: VecCreate(PETSC_COMM_SELF, &subCoordinates);
2948: PetscObjectGetName((PetscObject)coordinates,&name);
2949: PetscObjectSetName((PetscObject)subCoordinates,name);
2950: VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
2951: VecSetType(subCoordinates,VECSTANDARD);
2952: VecGetArray(coordinates, &coords);
2953: VecGetArray(subCoordinates, &subCoords);
2954: for (v = 0; v < numSubPoints[0]; ++v) {
2955: const PetscInt vertex = subpoints[0][v];
2956: const PetscInt subvertex = firstSubPoint[0]+v;
2957: PetscInt dof, off, sdof, soff, d;
2959: PetscSectionGetDof(coordSection, vertex, &dof);
2960: PetscSectionGetOffset(coordSection, vertex, &off);
2961: PetscSectionGetDof(subCoordSection, subvertex, &sdof);
2962: PetscSectionGetOffset(subCoordSection, subvertex, &soff);
2963: if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
2964: for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
2965: }
2966: VecRestoreArray(coordinates, &coords);
2967: VecRestoreArray(subCoordinates, &subCoords);
2968: DMSetCoordinatesLocal(subdm, subCoordinates);
2969: VecDestroy(&subCoordinates);
2970: }
2971: /* Build SF: We need this complexity because subpoints might not be selected on the owning process */
2972: {
2973: PetscSF sfPoint, sfPointSub;
2974: IS subpIS;
2975: const PetscSFNode *remotePoints;
2976: PetscSFNode *sremotePoints, *newLocalPoints, *newOwners;
2977: const PetscInt *localPoints, *subpoints;
2978: PetscInt *slocalPoints;
2979: PetscInt numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl, ll, pStart, pEnd, p;
2980: PetscMPIInt rank;
2982: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
2983: DMGetPointSF(dm, &sfPoint);
2984: DMGetPointSF(subdm, &sfPointSub);
2985: DMPlexGetChart(dm, &pStart, &pEnd);
2986: DMPlexGetChart(subdm, NULL, &numSubroots);
2987: DMPlexCreateSubpointIS(subdm, &subpIS);
2988: if (subpIS) {
2989: ISGetIndices(subpIS, &subpoints);
2990: ISGetLocalSize(subpIS, &numSubpoints);
2991: }
2992: PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
2993: if (numRoots >= 0) {
2994: PetscMalloc2(pEnd-pStart,&newLocalPoints,numRoots,&newOwners);
2995: for (p = 0; p < pEnd-pStart; ++p) {
2996: newLocalPoints[p].rank = -2;
2997: newLocalPoints[p].index = -2;
2998: }
2999: /* Set subleaves */
3000: for (l = 0; l < numLeaves; ++l) {
3001: const PetscInt point = localPoints[l];
3002: const PetscInt subpoint = DMPlexFilterPoint_Internal(point, 0, numSubpoints, subpoints);
3004: if (subpoint < 0) continue;
3005: newLocalPoints[point-pStart].rank = rank;
3006: newLocalPoints[point-pStart].index = subpoint;
3007: ++numSubleaves;
3008: }
3009: /* Must put in owned subpoints */
3010: for (p = pStart; p < pEnd; ++p) {
3011: const PetscInt subpoint = DMPlexFilterPoint_Internal(p, 0, numSubpoints, subpoints);
3013: if (subpoint < 0) {
3014: newOwners[p-pStart].rank = -3;
3015: newOwners[p-pStart].index = -3;
3016: } else {
3017: newOwners[p-pStart].rank = rank;
3018: newOwners[p-pStart].index = subpoint;
3019: }
3020: }
3021: PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
3022: PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
3023: PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
3024: PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
3025: PetscMalloc1(numSubleaves, &slocalPoints);
3026: PetscMalloc1(numSubleaves, &sremotePoints);
3027: for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) {
3028: const PetscInt point = localPoints[l];
3029: const PetscInt subpoint = DMPlexFilterPoint_Internal(point, 0, numSubpoints, subpoints);
3031: if (subpoint < 0) continue;
3032: if (newLocalPoints[point].rank == rank) {++ll; continue;}
3033: slocalPoints[sl] = subpoint;
3034: sremotePoints[sl].rank = newLocalPoints[point].rank;
3035: sremotePoints[sl].index = newLocalPoints[point].index;
3036: if (sremotePoints[sl].rank < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %d", point);
3037: if (sremotePoints[sl].index < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %d", point);
3038: ++sl;
3039: }
3040: if (sl + ll != numSubleaves) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %d + %d != %d", sl, ll, numSubleaves);
3041: PetscFree2(newLocalPoints,newOwners);
3042: PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER);
3043: }
3044: if (subpIS) {
3045: ISRestoreIndices(subpIS, &subpoints);
3046: ISDestroy(&subpIS);
3047: }
3048: }
3049: /* Cleanup */
3050: for (d = 0; d <= dim; ++d) {
3051: if (subpointIS[d]) {ISRestoreIndices(subpointIS[d], &subpoints[d]);}
3052: ISDestroy(&subpointIS[d]);
3053: }
3054: PetscFree4(numSubPoints,firstSubPoint,subpointIS,subpoints);
3055: return(0);
3056: }
3060: static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm)
3061: {
3065: DMPlexCreateSubmeshGeneric_Interpolated(dm, vertexLabel, value, PETSC_FALSE, 1, subdm);
3066: return(0);
3067: }
3071: /*@
3072: DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label
3074: Input Parameters:
3075: + dm - The original mesh
3076: . vertexLabel - The DMLabel marking vertices contained in the surface
3077: - value - The label value to use
3079: Output Parameter:
3080: . subdm - The surface mesh
3082: Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().
3084: Level: developer
3086: .seealso: DMPlexGetSubpointMap(), DMGetLabel(), DMLabelSetValue()
3087: @*/
3088: PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, DM *subdm)
3089: {
3090: PetscInt dim, depth;
3096: DMGetDimension(dm, &dim);
3097: DMPlexGetDepth(dm, &depth);
3098: DMCreate(PetscObjectComm((PetscObject)dm), subdm);
3099: DMSetType(*subdm, DMPLEX);
3100: DMSetDimension(*subdm, dim-1);
3101: if (depth == dim) {
3102: DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, *subdm);
3103: } else {
3104: DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm);
3105: }
3106: return(0);
3107: }
3111: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm)
3112: {
3113: MPI_Comm comm;
3114: DMLabel subpointMap;
3115: IS subvertexIS;
3116: const PetscInt *subVertices;
3117: PetscInt numSubVertices, firstSubVertex, numSubCells, *subCells = NULL;
3118: PetscInt *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV;
3119: PetscInt cMax, c, f;
3120: PetscErrorCode ierr;
3123: PetscObjectGetComm((PetscObject)dm, &comm);
3124: /* Create subpointMap which marks the submesh */
3125: DMLabelCreate("subpoint_map", &subpointMap);
3126: DMPlexSetSubpointMap(subdm, subpointMap);
3127: DMLabelDestroy(&subpointMap);
3128: DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm);
3129: /* Setup chart */
3130: DMLabelGetStratumSize(subpointMap, 0, &numSubVertices);
3131: DMLabelGetStratumSize(subpointMap, 2, &numSubCells);
3132: DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVertices);
3133: DMPlexSetVTKCellHeight(subdm, 1);
3134: /* Set cone sizes */
3135: firstSubVertex = numSubCells;
3136: firstSubFace = numSubCells+numSubVertices;
3137: newFacePoint = firstSubFace;
3138: DMLabelGetStratumIS(subpointMap, 0, &subvertexIS);
3139: if (subvertexIS) {ISGetIndices(subvertexIS, &subVertices);}
3140: for (c = 0; c < numSubCells; ++c) {
3141: DMPlexSetConeSize(subdm, c, 1);
3142: }
3143: for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
3144: DMPlexSetConeSize(subdm, f, nFV);
3145: }
3146: DMSetUp(subdm);
3147: /* Create face cones */
3148: DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
3149: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
3150: DMGetWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
3151: for (c = 0; c < numSubCells; ++c) {
3152: const PetscInt cell = subCells[c];
3153: const PetscInt subcell = c;
3154: const PetscInt *cone, *cells;
3155: PetscInt numCells, subVertex, p, v;
3157: if (cell < cMax) continue;
3158: DMPlexGetCone(dm, cell, &cone);
3159: for (v = 0; v < nFV; ++v) {
3160: PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex);
3161: subface[v] = firstSubVertex+subVertex;
3162: }
3163: DMPlexSetCone(subdm, newFacePoint, subface);
3164: DMPlexSetCone(subdm, subcell, &newFacePoint);
3165: DMPlexGetJoin(dm, nFV, cone, &numCells, &cells);
3166: /* Not true in parallel
3167: if (numCells != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
3168: for (p = 0; p < numCells; ++p) {
3169: PetscInt negsubcell;
3171: if (cells[p] >= cMax) continue;
3172: /* I know this is a crap search */
3173: for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) {
3174: if (subCells[negsubcell] == cells[p]) break;
3175: }
3176: if (negsubcell == numSubCells) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %d", cell);
3177: DMPlexSetCone(subdm, negsubcell, &newFacePoint);
3178: }
3179: DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells);
3180: ++newFacePoint;
3181: }
3182: DMRestoreWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
3183: DMPlexSymmetrize(subdm);
3184: DMPlexStratify(subdm);
3185: /* Build coordinates */
3186: {
3187: PetscSection coordSection, subCoordSection;
3188: Vec coordinates, subCoordinates;
3189: PetscScalar *coords, *subCoords;
3190: PetscInt numComp, coordSize, v;
3191: const char *name;
3193: DMGetCoordinateSection(dm, &coordSection);
3194: DMGetCoordinatesLocal(dm, &coordinates);
3195: DMGetCoordinateSection(subdm, &subCoordSection);
3196: PetscSectionSetNumFields(subCoordSection, 1);
3197: PetscSectionGetFieldComponents(coordSection, 0, &numComp);
3198: PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
3199: PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);
3200: for (v = 0; v < numSubVertices; ++v) {
3201: const PetscInt vertex = subVertices[v];
3202: const PetscInt subvertex = firstSubVertex+v;
3203: PetscInt dof;
3205: PetscSectionGetDof(coordSection, vertex, &dof);
3206: PetscSectionSetDof(subCoordSection, subvertex, dof);
3207: PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
3208: }
3209: PetscSectionSetUp(subCoordSection);
3210: PetscSectionGetStorageSize(subCoordSection, &coordSize);
3211: VecCreate(PETSC_COMM_SELF, &subCoordinates);
3212: PetscObjectGetName((PetscObject)coordinates,&name);
3213: PetscObjectSetName((PetscObject)subCoordinates,name);
3214: VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
3215: VecSetType(subCoordinates,VECSTANDARD);
3216: VecGetArray(coordinates, &coords);
3217: VecGetArray(subCoordinates, &subCoords);
3218: for (v = 0; v < numSubVertices; ++v) {
3219: const PetscInt vertex = subVertices[v];
3220: const PetscInt subvertex = firstSubVertex+v;
3221: PetscInt dof, off, sdof, soff, d;
3223: PetscSectionGetDof(coordSection, vertex, &dof);
3224: PetscSectionGetOffset(coordSection, vertex, &off);
3225: PetscSectionGetDof(subCoordSection, subvertex, &sdof);
3226: PetscSectionGetOffset(subCoordSection, subvertex, &soff);
3227: if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
3228: for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
3229: }
3230: VecRestoreArray(coordinates, &coords);
3231: VecRestoreArray(subCoordinates, &subCoords);
3232: DMSetCoordinatesLocal(subdm, subCoordinates);
3233: VecDestroy(&subCoordinates);
3234: }
3235: /* Build SF */
3236: CHKMEMQ;
3237: {
3238: PetscSF sfPoint, sfPointSub;
3239: const PetscSFNode *remotePoints;
3240: PetscSFNode *sremotePoints, *newLocalPoints, *newOwners;
3241: const PetscInt *localPoints;
3242: PetscInt *slocalPoints;
3243: PetscInt numRoots, numLeaves, numSubRoots = numSubCells+numSubFaces+numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd;
3244: PetscMPIInt rank;
3246: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
3247: DMGetPointSF(dm, &sfPoint);
3248: DMGetPointSF(subdm, &sfPointSub);
3249: DMPlexGetChart(dm, &pStart, &pEnd);
3250: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
3251: PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
3252: if (numRoots >= 0) {
3253: /* Only vertices should be shared */
3254: PetscMalloc2(pEnd-pStart,&newLocalPoints,numRoots,&newOwners);
3255: for (p = 0; p < pEnd-pStart; ++p) {
3256: newLocalPoints[p].rank = -2;
3257: newLocalPoints[p].index = -2;
3258: }
3259: /* Set subleaves */
3260: for (l = 0; l < numLeaves; ++l) {
3261: const PetscInt point = localPoints[l];
3262: const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);
3264: if ((point < vStart) && (point >= vEnd)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %d", point);
3265: if (subPoint < 0) continue;
3266: newLocalPoints[point-pStart].rank = rank;
3267: newLocalPoints[point-pStart].index = subPoint;
3268: ++numSubLeaves;
3269: }
3270: /* Must put in owned subpoints */
3271: for (p = pStart; p < pEnd; ++p) {
3272: const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices);
3274: if (subPoint < 0) {
3275: newOwners[p-pStart].rank = -3;
3276: newOwners[p-pStart].index = -3;
3277: } else {
3278: newOwners[p-pStart].rank = rank;
3279: newOwners[p-pStart].index = subPoint;
3280: }
3281: }
3282: PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
3283: PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
3284: PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
3285: PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
3286: PetscMalloc1(numSubLeaves, &slocalPoints);
3287: PetscMalloc1(numSubLeaves, &sremotePoints);
3288: for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) {
3289: const PetscInt point = localPoints[l];
3290: const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);
3292: if (subPoint < 0) continue;
3293: if (newLocalPoints[point].rank == rank) {++ll; continue;}
3294: slocalPoints[sl] = subPoint;
3295: sremotePoints[sl].rank = newLocalPoints[point].rank;
3296: sremotePoints[sl].index = newLocalPoints[point].index;
3297: if (sremotePoints[sl].rank < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %d", point);
3298: if (sremotePoints[sl].index < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %d", point);
3299: ++sl;
3300: }
3301: PetscFree2(newLocalPoints,newOwners);
3302: if (sl + ll != numSubLeaves) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %d + %d != %d", sl, ll, numSubLeaves);
3303: PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER);
3304: }
3305: }
3306: CHKMEMQ;
3307: /* Cleanup */
3308: if (subvertexIS) {ISRestoreIndices(subvertexIS, &subVertices);}
3309: ISDestroy(&subvertexIS);
3310: PetscFree(subCells);
3311: return(0);
3312: }
3316: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DM subdm)
3317: {
3318: DMLabel label = NULL;
3322: if (labelname) {DMGetLabel(dm, labelname, &label);}
3323: DMPlexCreateSubmeshGeneric_Interpolated(dm, label, value, PETSC_TRUE, 1, subdm);
3324: return(0);
3325: }
3329: /*
3330: DMPlexCreateCohesiveSubmesh - Extract from a mesh with cohesive cells the hypersurface defined by one face of the cells. Optionally, a Label an be given to restrict the cells.
3332: Input Parameters:
3333: + dm - The original mesh
3334: . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells
3335: . label - A label name, or NULL
3336: - value - A label value
3338: Output Parameter:
3339: . subdm - The surface mesh
3341: Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().
3343: Level: developer
3345: .seealso: DMPlexGetSubpointMap(), DMPlexCreateSubmesh()
3346: */
3347: PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm)
3348: {
3349: PetscInt dim, depth;
3355: DMGetDimension(dm, &dim);
3356: DMPlexGetDepth(dm, &depth);
3357: DMCreate(PetscObjectComm((PetscObject)dm), subdm);
3358: DMSetType(*subdm, DMPLEX);
3359: DMSetDimension(*subdm, dim-1);
3360: if (depth == dim) {
3361: DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm);
3362: } else {
3363: DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm);
3364: }
3365: return(0);
3366: }
3370: /*@
3371: DMPlexFilter - Extract a subset of mesh cells defined by a label as a separate mesh
3373: Input Parameters:
3374: + dm - The original mesh
3375: . cellLabel - The DMLabel marking cells contained in the new mesh
3376: - value - The label value to use
3378: Output Parameter:
3379: . subdm - The new mesh
3381: Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().
3383: Level: developer
3385: .seealso: DMPlexGetSubpointMap(), DMGetLabel(), DMLabelSetValue()
3386: @*/
3387: PetscErrorCode DMPlexFilter(DM dm, DMLabel cellLabel, PetscInt value, DM *subdm)
3388: {
3389: PetscInt dim;
3395: DMGetDimension(dm, &dim);
3396: DMCreate(PetscObjectComm((PetscObject) dm), subdm);
3397: DMSetType(*subdm, DMPLEX);
3398: DMSetDimension(*subdm, dim);
3399: /* Extract submesh in place, could be empty on some procs, could have inconsistency if procs do not both extract a shared cell */
3400: DMPlexCreateSubmeshGeneric_Interpolated(dm, cellLabel, value, PETSC_FALSE, 0, *subdm);
3401: return(0);
3402: }
3406: /*@
3407: DMPlexGetSubpointMap - Returns a DMLabel with point dimension as values
3409: Input Parameter:
3410: . dm - The submesh DM
3412: Output Parameter:
3413: . subpointMap - The DMLabel of all the points from the original mesh in this submesh, or NULL if this is not a submesh
3415: Level: developer
3417: .seealso: DMPlexCreateSubmesh(), DMPlexCreateSubpointIS()
3418: @*/
3419: PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap)
3420: {
3424: *subpointMap = ((DM_Plex*) dm->data)->subpointMap;
3425: return(0);
3426: }
3430: /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
3431: PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap)
3432: {
3433: DM_Plex *mesh = (DM_Plex *) dm->data;
3434: DMLabel tmp;
3439: tmp = mesh->subpointMap;
3440: mesh->subpointMap = subpointMap;
3441: ++mesh->subpointMap->refct;
3442: DMLabelDestroy(&tmp);
3443: return(0);
3444: }
3448: /*@
3449: DMPlexCreateSubpointIS - Creates an IS covering the entire subdm chart with the original points as data
3451: Input Parameter:
3452: . dm - The submesh DM
3454: Output Parameter:
3455: . subpointIS - The IS of all the points from the original mesh in this submesh, or NULL if this is not a submesh
3457: Note: This IS is guaranteed to be sorted by the construction of the submesh
3459: Level: developer
3461: .seealso: DMPlexCreateSubmesh(), DMPlexGetSubpointMap()
3462: @*/
3463: PetscErrorCode DMPlexCreateSubpointIS(DM dm, IS *subpointIS)
3464: {
3465: MPI_Comm comm;
3466: DMLabel subpointMap;
3467: IS is;
3468: const PetscInt *opoints;
3469: PetscInt *points, *depths;
3470: PetscInt depth, depStart, depEnd, d, pStart, pEnd, p, n, off;
3471: PetscErrorCode ierr;
3476: PetscObjectGetComm((PetscObject)dm,&comm);
3477: *subpointIS = NULL;
3478: DMPlexGetSubpointMap(dm, &subpointMap);
3479: DMPlexGetDepth(dm, &depth);
3480: if (subpointMap && depth >= 0) {
3481: DMPlexGetChart(dm, &pStart, &pEnd);
3482: if (pStart) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %d", pStart);
3483: DMGetWorkArray(dm, depth+1, PETSC_INT, &depths);
3484: depths[0] = depth;
3485: depths[1] = 0;
3486: for(d = 2; d <= depth; ++d) {depths[d] = depth+1 - d;}
3487: PetscMalloc1(pEnd, &points);
3488: for(d = 0, off = 0; d <= depth; ++d) {
3489: const PetscInt dep = depths[d];
3491: DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd);
3492: DMLabelGetStratumSize(subpointMap, dep, &n);
3493: if (((d < 2) && (depth > 1)) || (d == 1)) { /* Only check vertices and cells for now since the map is broken for others */
3494: if (n != depEnd-depStart) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %d at depth %d should be %d", n, dep, depEnd-depStart);
3495: } else {
3496: if (!n) {
3497: if (d == 0) {
3498: /* Missing cells */
3499: for(p = 0; p < depEnd-depStart; ++p, ++off) points[off] = -1;
3500: } else {
3501: /* Missing faces */
3502: for(p = 0; p < depEnd-depStart; ++p, ++off) points[off] = PETSC_MAX_INT;
3503: }
3504: }
3505: }
3506: if (n) {
3507: DMLabelGetStratumIS(subpointMap, dep, &is);
3508: ISGetIndices(is, &opoints);
3509: for(p = 0; p < n; ++p, ++off) points[off] = opoints[p];
3510: ISRestoreIndices(is, &opoints);
3511: ISDestroy(&is);
3512: }
3513: }
3514: DMRestoreWorkArray(dm, depth+1, PETSC_INT, &depths);
3515: if (off != pEnd) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %d should be %d", off, pEnd);
3516: ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS);
3517: }
3518: return(0);
3519: }