Actual source code: plexsubmesh.c

petsc-dev 2014-02-02
Report Typos and Errors
  1: #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
  2: #include <petscsf.h>

  6: /*@
  7:   DMPlexMarkBoundaryFaces - Mark all faces on the boundary

  9:   Not Collective

 11:   Input Parameter:
 12: . dm - The original DM

 14:   Output Parameter:
 15: . label - The DMLabel marking boundary faces with value 1

 17:   Level: developer

 19: .seealso: DMLabelCreate(), DMPlexCreateLabel()
 20: @*/
 21: PetscErrorCode DMPlexMarkBoundaryFaces(DM dm, DMLabel label)
 22: {
 23:   PetscInt       fStart, fEnd, f;

 28:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
 29:   for (f = fStart; f < fEnd; ++f) {
 30:     PetscInt supportSize;

 32:     DMPlexGetSupportSize(dm, f, &supportSize);
 33:     if (supportSize == 1) {
 34:       DMLabelSetValue(label, f, 1);
 35:     }
 36:   }
 37:   return(0);
 38: }

 42: /*@
 43:   DMPlexLabelComplete - Starting with a label marking points on a surface, we add the transitive closure to the surface

 45:   Input Parameters:
 46: + dm - The DM
 47: - label - A DMLabel marking the surface points

 49:   Output Parameter:
 50: . label - A DMLabel marking all surface points in the transitive closure

 52:   Level: developer

 54: .seealso: DMPlexLabelCohesiveComplete()
 55: @*/
 56: PetscErrorCode DMPlexLabelComplete(DM dm, DMLabel label)
 57: {
 58:   IS              valueIS;
 59:   const PetscInt *values;
 60:   PetscInt        numValues, v;
 61:   PetscErrorCode  ierr;

 64:   DMLabelGetNumValues(label, &numValues);
 65:   DMLabelGetValueIS(label, &valueIS);
 66:   ISGetIndices(valueIS, &values);
 67:   for (v = 0; v < numValues; ++v) {
 68:     IS              pointIS;
 69:     const PetscInt *points;
 70:     PetscInt        numPoints, p;

 72:     DMLabelGetStratumSize(label, values[v], &numPoints);
 73:     DMLabelGetStratumIS(label, values[v], &pointIS);
 74:     ISGetIndices(pointIS, &points);
 75:     for (p = 0; p < numPoints; ++p) {
 76:       PetscInt *closure = NULL;
 77:       PetscInt  closureSize, c;

 79:       DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);
 80:       for (c = 0; c < closureSize*2; c += 2) {
 81:         DMLabelSetValue(label, closure[c], values[v]);
 82:       }
 83:       DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);
 84:     }
 85:     ISRestoreIndices(pointIS, &points);
 86:     ISDestroy(&pointIS);
 87:   }
 88:   ISRestoreIndices(valueIS, &values);
 89:   ISDestroy(&valueIS);
 90:   return(0);
 91: }

 95: PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Internal(PetscInt p, PetscInt depth, PetscInt depthMax[], PetscInt depthEnd[], PetscInt depthShift[])
 96: {
 97:   if (depth < 0) return p;
 98:   /* Normal Cells                 */ if (p < depthMax[depth])                return p;
 99:   /* Hybrid Cells+Normal Vertices */ if (p < depthMax[0])                    return p + depthShift[depth];
100:   /* Hybrid Vertices+Normal Faces */ if (depth < 2 || p < depthMax[depth-1]) return p + depthShift[depth] + depthShift[0];
101:   /* Hybrid Faces+Normal Edges    */ if (depth < 3 || p < depthMax[depth-2]) return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
102:   /* Hybrid Edges                 */                                         return p + depthShift[depth] + depthShift[0] + depthShift[depth-1] + depthShift[depth-2];
103: }

107: static PetscErrorCode DMPlexShiftSizes_Internal(DM dm, PetscInt depthShift[], DM dmNew)
108: {
109:   PetscInt      *depthMax, *depthEnd;
110:   PetscInt       depth = 0, d, pStart, pEnd, p;

114:   DMPlexGetDepth(dm, &depth);
115:   if (depth < 0) return(0);
116:   PetscMalloc2(depth+1,&depthMax,depth+1,&depthEnd);
117:   /* Step 1: Expand chart */
118:   DMPlexGetChart(dm, &pStart, &pEnd);
119:   DMPlexGetHybridBounds(dm, &depthMax[depth], depth > 0 ? &depthMax[depth-1] : NULL, &depthMax[1], &depthMax[0]);
120:   for (d = 0; d <= depth; ++d) {
121:     pEnd += depthShift[d];
122:     DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);
123:     depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
124:   }
125:   DMPlexSetChart(dmNew, pStart, pEnd);
126:   /* Step 2: Set cone and support sizes */
127:   for (d = 0; d <= depth; ++d) {
128:     DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
129:     for (p = pStart; p < pEnd; ++p) {
130:       PetscInt newp = DMPlexShiftPoint_Internal(p, depth, depthMax, depthEnd, depthShift);
131:       PetscInt size;

133:       DMPlexGetConeSize(dm, p, &size);
134:       DMPlexSetConeSize(dmNew, newp, size);
135:       DMPlexGetSupportSize(dm, p, &size);
136:       DMPlexSetSupportSize(dmNew, newp, size);
137:     }
138:   }
139:   PetscFree2(depthMax,depthEnd);
140:   return(0);
141: }

145: static PetscErrorCode DMPlexShiftPoints_Internal(DM dm, PetscInt depthShift[], DM dmNew)
146: {
147:   PetscInt      *depthEnd, *depthMax, *newpoints;
148:   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, pStart, pEnd, p;

152:   DMPlexGetDepth(dm, &depth);
153:   if (depth < 0) return(0);
154:   DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
155:   DMPlexGetMaxSizes(dmNew, &maxConeSizeNew, &maxSupportSizeNew);
156:   PetscMalloc3(depth+1,&depthEnd,depth+1,&depthMax,PetscMax(PetscMax(maxConeSize, maxSupportSize), PetscMax(maxConeSizeNew, maxSupportSizeNew)),&newpoints);
157:   DMPlexGetHybridBounds(dm, &depthMax[depth], depth > 0 ? &depthMax[depth-1] : NULL, &depthMax[1], &depthMax[0]);
158:   for (d = 0; d <= depth; ++d) {
159:     DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);
160:     depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
161:   }
162:   /* Step 5: Set cones and supports */
163:   DMPlexGetChart(dm, &pStart, &pEnd);
164:   for (p = pStart; p < pEnd; ++p) {
165:     const PetscInt *points = NULL, *orientations = NULL;
166:     PetscInt        size,sizeNew, i, newp = DMPlexShiftPoint_Internal(p, depth, depthMax, depthEnd, depthShift);

168:     DMPlexGetConeSize(dm, p, &size);
169:     DMPlexGetCone(dm, p, &points);
170:     DMPlexGetConeOrientation(dm, p, &orientations);
171:     for (i = 0; i < size; ++i) {
172:       newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthMax, depthEnd, depthShift);
173:     }
174:     DMPlexSetCone(dmNew, newp, newpoints);
175:     DMPlexSetConeOrientation(dmNew, newp, orientations);
176:     DMPlexGetSupportSize(dm, p, &size);
177:     DMPlexGetSupportSize(dmNew, newp, &sizeNew);
178:     DMPlexGetSupport(dm, p, &points);
179:     for (i = 0; i < size; ++i) {
180:       newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthMax, depthEnd, depthShift);
181:     }
182:     for (i = size; i < sizeNew; ++i) newpoints[i] = 0;
183:     DMPlexSetSupport(dmNew, newp, newpoints);
184:   }
185:   PetscFree3(depthEnd,depthMax,newpoints);
186:   return(0);
187: }

191: static PetscErrorCode DMPlexShiftCoordinates_Internal(DM dm, PetscInt depthShift[], DM dmNew)
192: {
193:   PetscSection   coordSection, newCoordSection;
194:   Vec            coordinates, newCoordinates;
195:   PetscScalar   *coords, *newCoords;
196:   PetscInt      *depthEnd, coordSize;
197:   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;

201:   DMPlexGetDimension(dm, &dim);
202:   DMPlexGetDepth(dm, &depth);
203:   PetscMalloc1((depth+1), &depthEnd);
204:   for (d = 0; d <= depth; ++d) {
205:     DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);
206:   }
207:   /* Step 8: Convert coordinates */
208:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
209:   DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);
210:   DMGetCoordinateSection(dm, &coordSection);
211:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);
212:   PetscSectionSetNumFields(newCoordSection, 1);
213:   PetscSectionSetFieldComponents(newCoordSection, 0, dim);
214:   PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);
215:   for (v = vStartNew; v < vEndNew; ++v) {
216:     PetscSectionSetDof(newCoordSection, v, dim);
217:     PetscSectionSetFieldDof(newCoordSection, v, 0, dim);
218:   }
219:   PetscSectionSetUp(newCoordSection);
220:   DMSetCoordinateSection(dmNew, newCoordSection);
221:   PetscSectionGetStorageSize(newCoordSection, &coordSize);
222:   VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);
223:   PetscObjectSetName((PetscObject) newCoordinates, "coordinates");
224:   VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);
225:   VecSetType(newCoordinates,VECSTANDARD);
226:   DMSetCoordinatesLocal(dmNew, newCoordinates);
227:   DMGetCoordinatesLocal(dm, &coordinates);
228:   VecGetArray(coordinates, &coords);
229:   VecGetArray(newCoordinates, &newCoords);
230:   for (v = vStart; v < vEnd; ++v) {
231:     PetscInt dof, off, noff, d;

233:     PetscSectionGetDof(coordSection, v, &dof);
234:     PetscSectionGetOffset(coordSection, v, &off);
235:     PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Internal(v, depth, depthEnd, depthEnd, depthShift), &noff);
236:     for (d = 0; d < dof; ++d) {
237:       newCoords[noff+d] = coords[off+d];
238:     }
239:   }
240:   VecRestoreArray(coordinates, &coords);
241:   VecRestoreArray(newCoordinates, &newCoords);
242:   VecDestroy(&newCoordinates);
243:   PetscSectionDestroy(&newCoordSection);
244:   PetscFree(depthEnd);
245:   return(0);
246: }

250: static PetscErrorCode DMPlexShiftSF_Internal(DM dm, PetscInt depthShift[], DM dmNew)
251: {
252:   PetscInt          *depthMax, *depthEnd;
253:   PetscInt           depth = 0, d;
254:   PetscSF            sfPoint, sfPointNew;
255:   const PetscSFNode *remotePoints;
256:   PetscSFNode       *gremotePoints;
257:   const PetscInt    *localPoints;
258:   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
259:   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
260:   PetscErrorCode     ierr;

263:   DMPlexGetDepth(dm, &depth);
264:   PetscMalloc2(depth+1,&depthMax,depth+1,&depthEnd);
265:   DMPlexGetHybridBounds(dm, depth >= 0 ? &depthMax[depth] : NULL, depth>1 ? &depthMax[depth-1] : NULL, depth>2 ? &depthMax[1] : NULL, depth >= 0 ? &depthMax[0] : NULL);
266:   for (d = 0; d <= depth; ++d) {
267:     totShift += depthShift[d];
268:     DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);
269:     depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
270:   }
271:   /* Step 9: Convert pointSF */
272:   DMGetPointSF(dm, &sfPoint);
273:   DMGetPointSF(dmNew, &sfPointNew);
274:   DMPlexGetChart(dm, &pStart, &pEnd);
275:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
276:   if (numRoots >= 0) {
277:     PetscMalloc2(numRoots,&newLocation,pEnd-pStart,&newRemoteLocation);
278:     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Internal(l, depth, depthMax, depthEnd, depthShift);
279:     PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);
280:     PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);
281:     PetscMalloc1(numLeaves,    &glocalPoints);
282:     PetscMalloc1(numLeaves, &gremotePoints);
283:     for (l = 0; l < numLeaves; ++l) {
284:       glocalPoints[l]        = DMPlexShiftPoint_Internal(localPoints[l], depth, depthMax, depthEnd, depthShift);
285:       gremotePoints[l].rank  = remotePoints[l].rank;
286:       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
287:     }
288:     PetscFree2(newLocation,newRemoteLocation);
289:     PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);
290:   }
291:   PetscFree2(depthMax,depthEnd);
292:   return(0);
293: }

297: static PetscErrorCode DMPlexShiftLabels_Internal(DM dm, PetscInt depthShift[], DM dmNew)
298: {
299:   PetscSF            sfPoint;
300:   DMLabel            vtkLabel, ghostLabel;
301:   PetscInt          *depthMax, *depthEnd;
302:   const PetscSFNode *leafRemote;
303:   const PetscInt    *leafLocal;
304:   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
305:   PetscMPIInt        rank;
306:   PetscErrorCode     ierr;

309:   DMPlexGetDepth(dm, &depth);
310:   PetscMalloc2(depth+1,&depthMax,depth+1,&depthEnd);
311:   DMPlexGetHybridBounds(dm, depth >= 0 ? &depthMax[depth] : NULL, depth>1 ? &depthMax[depth-1] : NULL, depth>2 ? &depthMax[1] : NULL, depth >= 0 ? &depthMax[0] : NULL);
312:   for (d = 0; d <= depth; ++d) {
313:     DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);
314:     depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
315:   }
316:   /* Step 10: Convert labels */
317:   DMPlexGetNumLabels(dm, &numLabels);
318:   for (l = 0; l < numLabels; ++l) {
319:     DMLabel         label, newlabel;
320:     const char     *lname;
321:     PetscBool       isDepth;
322:     IS              valueIS;
323:     const PetscInt *values;
324:     PetscInt        numValues, val;

326:     DMPlexGetLabelName(dm, l, &lname);
327:     PetscStrcmp(lname, "depth", &isDepth);
328:     if (isDepth) continue;
329:     DMPlexCreateLabel(dmNew, lname);
330:     DMPlexGetLabel(dm, lname, &label);
331:     DMPlexGetLabel(dmNew, lname, &newlabel);
332:     DMLabelGetValueIS(label, &valueIS);
333:     ISGetLocalSize(valueIS, &numValues);
334:     ISGetIndices(valueIS, &values);
335:     for (val = 0; val < numValues; ++val) {
336:       IS              pointIS;
337:       const PetscInt *points;
338:       PetscInt        numPoints, p;

340:       DMLabelGetStratumIS(label, values[val], &pointIS);
341:       ISGetLocalSize(pointIS, &numPoints);
342:       ISGetIndices(pointIS, &points);
343:       for (p = 0; p < numPoints; ++p) {
344:         const PetscInt newpoint = DMPlexShiftPoint_Internal(points[p], depth, depthMax, depthEnd, depthShift);

346:         DMLabelSetValue(newlabel, newpoint, values[val]);
347:       }
348:       ISRestoreIndices(pointIS, &points);
349:       ISDestroy(&pointIS);
350:     }
351:     ISRestoreIndices(valueIS, &values);
352:     ISDestroy(&valueIS);
353:   }
354:   PetscFree2(depthMax,depthEnd);
355:   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
356:   MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
357:   DMGetPointSF(dm, &sfPoint);
358:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
359:   PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);
360:   DMPlexCreateLabel(dmNew, "vtk");
361:   DMPlexCreateLabel(dmNew, "ghost");
362:   DMPlexGetLabel(dmNew, "vtk", &vtkLabel);
363:   DMPlexGetLabel(dmNew, "ghost", &ghostLabel);
364:   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
365:     for (; c < leafLocal[l] && c < cEnd; ++c) {
366:       DMLabelSetValue(vtkLabel, c, 1);
367:     }
368:     if (leafLocal[l] >= cEnd) break;
369:     if (leafRemote[l].rank == rank) {
370:       DMLabelSetValue(vtkLabel, c, 1);
371:     } else {
372:       DMLabelSetValue(ghostLabel, c, 2);
373:     }
374:   }
375:   for (; c < cEnd; ++c) {
376:     DMLabelSetValue(vtkLabel, c, 1);
377:   }
378:   if (0) {
379:     PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);
380:     DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);
381:     PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);
382:   }
383:   DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);
384:   for (f = fStart; f < fEnd; ++f) {
385:     PetscInt numCells;

387:     DMPlexGetSupportSize(dmNew, f, &numCells);
388:     if (numCells < 2) {
389:       DMLabelSetValue(ghostLabel, f, 1);
390:     } else {
391:       const PetscInt *cells = NULL;
392:       PetscInt        vA, vB;

394:       DMPlexGetSupport(dmNew, f, &cells);
395:       DMLabelGetValue(vtkLabel, cells[0], &vA);
396:       DMLabelGetValue(vtkLabel, cells[1], &vB);
397:       if (!vA && !vB) {DMLabelSetValue(ghostLabel, f, 1);}
398:     }
399:   }
400:   if (0) {
401:     PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);
402:     DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);
403:     PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);
404:   }
405:   return(0);
406: }

410: static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, DMLabel label, PetscInt *numGhostCells, DM gdm)
411: {
412:   IS              valueIS;
413:   const PetscInt *values;
414:   PetscInt       *depthShift;
415:   PetscInt        depth = 0, numFS, fs, fStart, fEnd, ghostCell, cEnd, c;
416:   PetscErrorCode  ierr;

419:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
420:   /* Count ghost cells */
421:   DMLabelGetValueIS(label, &valueIS);
422:   ISGetLocalSize(valueIS, &numFS);
423:   ISGetIndices(valueIS, &values);
424:   *numGhostCells = 0;
425:   for (fs = 0; fs < numFS; ++fs) {
426:     IS              faceIS;
427:     const PetscInt *faces;
428:     PetscInt        numFaces, f, numBdFaces = 0;

430:     DMLabelGetStratumIS(label, values[fs], &faceIS);
431:     ISGetLocalSize(faceIS, &numFaces);
432:     ISGetIndices(faceIS, &faces);
433:     for (f = 0; f < numFaces; ++f) {
434:       if ((faces[f] >= fStart) && (faces[f] < fEnd)) ++numBdFaces;
435:     }
436:     *numGhostCells += numBdFaces;
437:     ISDestroy(&faceIS);
438:   }
439:   DMPlexGetDepth(dm, &depth);
440:   PetscMalloc1((depth+1), &depthShift);
441:   PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));
442:   if (depth >= 0) depthShift[depth] = *numGhostCells;
443:   DMPlexShiftSizes_Internal(dm, depthShift, gdm);
444:   /* Step 3: Set cone/support sizes for new points */
445:   DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
446:   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
447:     DMPlexSetConeSize(gdm, c, 1);
448:   }
449:   for (fs = 0; fs < numFS; ++fs) {
450:     IS              faceIS;
451:     const PetscInt *faces;
452:     PetscInt        numFaces, f;

454:     DMLabelGetStratumIS(label, values[fs], &faceIS);
455:     ISGetLocalSize(faceIS, &numFaces);
456:     ISGetIndices(faceIS, &faces);
457:     for (f = 0; f < numFaces; ++f) {
458:       PetscInt size;

460:       if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
461:       DMPlexGetSupportSize(dm, faces[f], &size);
462:       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
463:       DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);
464:     }
465:     ISRestoreIndices(faceIS, &faces);
466:     ISDestroy(&faceIS);
467:   }
468:   /* Step 4: Setup ghosted DM */
469:   DMSetUp(gdm);
470:   DMPlexShiftPoints_Internal(dm, depthShift, gdm);
471:   /* Step 6: Set cones and supports for new points */
472:   ghostCell = cEnd;
473:   for (fs = 0; fs < numFS; ++fs) {
474:     IS              faceIS;
475:     const PetscInt *faces;
476:     PetscInt        numFaces, f;

478:     DMLabelGetStratumIS(label, values[fs], &faceIS);
479:     ISGetLocalSize(faceIS, &numFaces);
480:     ISGetIndices(faceIS, &faces);
481:     for (f = 0; f < numFaces; ++f) {
482:       PetscInt newFace = faces[f] + *numGhostCells;

484:       if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
485:       DMPlexSetCone(gdm, ghostCell, &newFace);
486:       DMPlexInsertSupport(gdm, newFace, 1, ghostCell);
487:       ++ghostCell;
488:     }
489:     ISRestoreIndices(faceIS, &faces);
490:     ISDestroy(&faceIS);
491:   }
492:   ISRestoreIndices(valueIS, &values);
493:   ISDestroy(&valueIS);
494:   /* Step 7: Stratify */
495:   DMPlexStratify(gdm);
496:   DMPlexShiftCoordinates_Internal(dm, depthShift, gdm);
497:   DMPlexShiftSF_Internal(dm, depthShift, gdm);
498:   DMPlexShiftLabels_Internal(dm, depthShift, gdm);
499:   PetscFree(depthShift);
500:   return(0);
501: }

505: /*@C
506:   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face

508:   Collective on dm

510:   Input Parameters:
511: + dm - The original DM
512: - labelName - The label specifying the boundary faces, or "Face Sets" if this is NULL

514:   Output Parameters:
515: + numGhostCells - The number of ghost cells added to the DM
516: - dmGhosted - The new DM

518:   Note: If no label exists of that name, one will be created marking all boundary faces

520:   Level: developer

522: .seealso: DMCreate()
523: @*/
524: PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
525: {
526:   DM             gdm;
527:   DMLabel        label;
528:   const char    *name = labelName ? labelName : "Face Sets";
529:   PetscInt       dim;

536:   DMCreate(PetscObjectComm((PetscObject)dm), &gdm);
537:   DMSetType(gdm, DMPLEX);
538:   DMPlexGetDimension(dm, &dim);
539:   DMPlexSetDimension(gdm, dim);
540:   DMPlexGetLabel(dm, name, &label);
541:   if (!label) {
542:     /* Get label for boundary faces */
543:     DMPlexCreateLabel(dm, name);
544:     DMPlexGetLabel(dm, name, &label);
545:     DMPlexMarkBoundaryFaces(dm, label);
546:   }
547:   DMPlexConstructGhostCells_Internal(dm, label, numGhostCells, gdm);
548:   DMSetFromOptions(gdm);
549:   *dmGhosted = gdm;
550:   return(0);
551: }

555: /*
556:   We are adding three kinds of points here:
557:     Replicated:     Copies of points which exist in the mesh, such as vertices identified across a fault
558:     Non-replicated: Points which exist on the fault, but are not replicated
559:     Hybrid:         Entirely new points, such as cohesive cells

561:   When creating subsequent cohesive cells, we shift the old hybrid cells to the end of the numbering at
562:   each depth so that the new split/hybrid points can be inserted as a block.
563: */
564: static PetscErrorCode DMPlexConstructCohesiveCells_Internal(DM dm, DMLabel label, DM sdm)
565: {
566:   MPI_Comm         comm;
567:   IS               valueIS;
568:   PetscInt         numSP = 0;       /* The number of depths for which we have replicated points */
569:   const PetscInt  *values;          /* List of depths for which we have replicated points */
570:   IS              *splitIS;
571:   IS              *unsplitIS;
572:   PetscInt        *numSplitPoints;     /* The number of replicated points at each depth */
573:   PetscInt        *numUnsplitPoints;   /* The number of non-replicated points at each depth which still give rise to hybrid points */
574:   PetscInt        *numHybridPoints;    /* The number of new hybrid points at each depth */
575:   PetscInt        *numHybridPointsOld; /* The number of existing hybrid points at each depth */
576:   const PetscInt **splitPoints;        /* Replicated points for each depth */
577:   const PetscInt **unsplitPoints;      /* Non-replicated points for each depth */
578:   PetscSection     coordSection;
579:   Vec              coordinates;
580:   PetscScalar     *coords;
581:   PetscInt         depths[4];          /* Depths in the order that plex points are numbered */
582:   PetscInt        *depthMax;           /* The first hybrid point at each depth in the original mesh */
583:   PetscInt        *depthEnd;           /* The point limit at each depth in the original mesh */
584:   PetscInt        *depthShift;         /* Number of replicated+hybrid points at each depth */
585:   PetscInt        *depthOffset;        /* Prefix sums of depthShift */
586:   PetscInt        *pMaxNew;            /* The first replicated point at each depth in the new mesh, hybrids come after this */
587:   PetscInt        *coneNew, *coneONew, *supportNew;
588:   PetscInt         shift = 100, shift2 = 200, depth = 0, dep, dim, d, sp, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, numLabels, vStart, vEnd, pEnd, p, v;
589:   PetscErrorCode   ierr;

592:   PetscObjectGetComm((PetscObject)dm,&comm);
593:   DMPlexGetDimension(dm, &dim);
594:   DMPlexGetDepth(dm, &depth);
595:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
596:   depths[0] = depth;
597:   depths[1] = 0;
598:   depths[2] = depth-1;
599:   depths[3] = 1;
600:   /* Count split points and add cohesive cells */
601:   DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
602:   PetscMalloc6(depth+1,&depthMax,depth+1,&depthEnd,depth+1,&depthShift,depth+1,&depthOffset,depth+1,&pMaxNew,depth+1,&numHybridPointsOld);
603:   PetscMalloc7(depth+1,&splitIS,depth+1,&unsplitIS,depth+1,&numSplitPoints,depth+1,&numUnsplitPoints,depth+1,&numHybridPoints,depth+1,&splitPoints,depth+1,&unsplitPoints);
604:   PetscMemzero(depthShift,  (depth+1) * sizeof(PetscInt));
605:   PetscMemzero(depthOffset, (depth+1) * sizeof(PetscInt));
606:   DMPlexGetHybridBounds(dm, depth >= 0 ? &depthMax[depth] : NULL, depth>1 ? &depthMax[depth-1] : NULL, depth>2 ? &depthMax[1] : NULL, depth >= 0 ? &depthMax[0] : NULL);
607:   for (d = 0; d <= depth; ++d) {
608:     DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);
609:     depthEnd[d]           = pMaxNew[d];
610:     depthMax[d]           = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
611:     numSplitPoints[d]     = 0;
612:     numUnsplitPoints[d]   = 0;
613:     numHybridPoints[d]    = 0;
614:     numHybridPointsOld[d] = depthMax[d] < 0 ? 0 : depthEnd[d] - depthMax[d];
615:     splitPoints[d]        = NULL;
616:     unsplitPoints[d]      = NULL;
617:     splitIS[d]            = NULL;
618:     unsplitIS[d]          = NULL;
619:   }
620:   if (label) {
621:     DMLabelGetValueIS(label, &valueIS);
622:     ISGetLocalSize(valueIS, &numSP);
623:     ISGetIndices(valueIS, &values);
624:   }
625:   for (sp = 0; sp < numSP; ++sp) {
626:     const PetscInt dep = values[sp];

628:     if ((dep < 0) || (dep > depth)) continue;
629:     DMLabelGetStratumIS(label, dep, &splitIS[dep]);
630:     if (splitIS[dep]) {
631:       ISGetLocalSize(splitIS[dep], &numSplitPoints[dep]);
632:       ISGetIndices(splitIS[dep], &splitPoints[dep]);
633:     }
634:     DMLabelGetStratumIS(label, shift2+dep, &unsplitIS[dep]);
635:     if (unsplitIS[dep]) {
636:       ISGetLocalSize(unsplitIS[dep], &numUnsplitPoints[dep]);
637:       ISGetIndices(unsplitIS[dep], &unsplitPoints[dep]);
638:     }
639:   }
640:   /* Calculate number of hybrid points */
641:   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   */
642:   for (d = 0; d <= depth; ++d) depthShift[d]          = numSplitPoints[d] + numHybridPoints[d];
643:   for (d = 1; d <= depth; ++d) depthOffset[depths[d]] = depthOffset[depths[d-1]] + depthShift[depths[d-1]];
644:   for (d = 0; d <= depth; ++d) pMaxNew[d]            += depthOffset[d] - numHybridPointsOld[d];
645:   DMPlexShiftSizes_Internal(dm, depthShift, sdm);
646:   /* Step 3: Set cone/support sizes for new points */
647:   for (dep = 0; dep <= depth; ++dep) {
648:     for (p = 0; p < numSplitPoints[dep]; ++p) {
649:       const PetscInt  oldp   = splitPoints[dep][p];
650:       const PetscInt  newp   = DMPlexShiftPoint_Internal(oldp, depth, depthMax, depthEnd, depthShift) /*oldp + depthOffset[dep]*/;
651:       const PetscInt  splitp = p    + pMaxNew[dep];
652:       const PetscInt *support;
653:       PetscInt        coneSize, supportSize, qf, qn, qp, e;

655:       DMPlexGetConeSize(dm, oldp, &coneSize);
656:       DMPlexSetConeSize(sdm, splitp, coneSize);
657:       DMPlexGetSupportSize(dm, oldp, &supportSize);
658:       DMPlexSetSupportSize(sdm, splitp, supportSize);
659:       if (dep == depth-1) {
660:         const PetscInt hybcell = p + pMaxNew[dep+1] + numSplitPoints[dep+1];

662:         /* Add cohesive cells, they are prisms */
663:         DMPlexSetConeSize(sdm, hybcell, 2 + coneSize);
664:       } else if (dep == 0) {
665:         const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1];

667:         DMPlexGetSupport(dm, oldp, &support);
668:         for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
669:           PetscInt val;

671:           DMLabelGetValue(label, support[e], &val);
672:           if (val == 1) ++qf;
673:           if ((val == 1) || (val ==  (shift + 1))) ++qn;
674:           if ((val == 1) || (val == -(shift + 1))) ++qp;
675:         }
676:         /* Split old vertex: Edges into original vertex and new cohesive edge */
677:         DMPlexSetSupportSize(sdm, newp, qn+1);
678:         /* Split new vertex: Edges into split vertex and new cohesive edge */
679:         DMPlexSetSupportSize(sdm, splitp, qp+1);
680:         /* Add hybrid edge */
681:         DMPlexSetConeSize(sdm, hybedge, 2);
682:         DMPlexSetSupportSize(sdm, hybedge, qf);
683:       } else if (dep == dim-2) {
684:         const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1];

686:         DMPlexGetSupport(dm, oldp, &support);
687:         for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
688:           PetscInt val;

690:           DMLabelGetValue(label, support[e], &val);
691:           if (val == dim-1) ++qf;
692:           if ((val == dim-1) || (val ==  (shift + dim-1))) ++qn;
693:           if ((val == dim-1) || (val == -(shift + dim-1))) ++qp;
694:         }
695:         /* Split old edge: Faces into original edge and cohesive face (positive side?) */
696:         DMPlexSetSupportSize(sdm, newp, qn+1);
697:         /* Split new edge: Faces into split edge and cohesive face (negative side?) */
698:         DMPlexSetSupportSize(sdm, splitp, qp+1);
699:         /* Add hybrid face */
700:         DMPlexSetConeSize(sdm, hybface, 4);
701:         DMPlexSetSupportSize(sdm, hybface, qf);
702:       }
703:     }
704:   }
705:   for (dep = 0; dep <= depth; ++dep) {
706:     for (p = 0; p < numUnsplitPoints[dep]; ++p) {
707:       const PetscInt  oldp   = unsplitPoints[dep][p];
708:       const PetscInt  newp   = DMPlexShiftPoint_Internal(oldp, depth, depthMax, depthEnd, depthShift) /*oldp + depthOffset[dep]*/;
709:       const PetscInt *support;
710:       PetscInt        coneSize, supportSize, qf, qn, qp, e;

712:       DMPlexGetConeSize(dm, oldp, &coneSize);
713:       DMPlexGetSupportSize(dm, oldp, &supportSize);
714:       if (dep == 0) {
715:         const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];

717:         /* Unsplit vertex: Edges into original vertex, split edge, and new cohesive edge twice */
718:         DMPlexSetSupportSize(sdm, newp, supportSize+3);
719:         /* Add hybrid edge */
720:         DMPlexSetConeSize(sdm, hybedge, 2);
721:         DMPlexGetSupport(dm, oldp, &support);
722:         for (e = 0, qf = 0; e < supportSize; ++e) {
723:           PetscInt val;

725:           DMLabelGetValue(label, support[e], &val);
726:           /* Split and unsplit edges produce hybrid faces */
727:           if ((val == 1) || (val ==  (shift2 + 1))) ++qf;
728:         }
729:         DMPlexSetSupportSize(sdm, hybedge, qf);
730:       } else if (dep == dim-2) {
731:         const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];

733:         DMPlexGetSupport(dm, oldp, &support);
734:         for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
735:           PetscInt val;

737:           DMLabelGetValue(label, support[e], &val);
738:           if (val == dim-1) ++qf;
739:           if ((val == dim-1) || (val ==  (shift + dim-1))) ++qn;
740:           if ((val == dim-1) || (val == -(shift + dim-1))) ++qp;
741:         }
742:         /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */
743:         DMPlexSetSupportSize(sdm, newp, supportSize+3);
744:         /* Add hybrid face */
745:         DMPlexSetConeSize(sdm, hybface, 4);
746:         /* TODO: Here we should check for neighboring faults for which this is unsplit */
747:         DMPlexSetSupportSize(sdm, hybface, 1);
748:       }
749:     }
750:   }
751:   /* Step 4: Setup split DM */
752:   DMSetUp(sdm);
753:   DMPlexShiftPoints_Internal(dm, depthShift, sdm);
754:   DMPlexGetMaxSizes(sdm, &maxConeSizeNew, &maxSupportSizeNew);
755:   PetscMalloc3(PetscMax(maxConeSize, maxConeSizeNew)*3,&coneNew,PetscMax(maxConeSize, maxConeSizeNew)*3,&coneONew,PetscMax(maxSupportSize, maxSupportSizeNew),&supportNew);
756:   /* Step 6: Set cones and supports for new points */
757:   for (dep = 0; dep <= depth; ++dep) {
758:     for (p = 0; p < numSplitPoints[dep]; ++p) {
759:       const PetscInt  oldp   = splitPoints[dep][p];
760:       const PetscInt  newp   = DMPlexShiftPoint_Internal(oldp, depth, depthMax, depthEnd, depthShift) /*oldp + depthOffset[dep]*/;
761:       const PetscInt  splitp = p    + pMaxNew[dep];
762:       const PetscInt *cone, *support, *ornt;
763:       PetscInt        coneSize, supportSize, q, qf, qn, qp, v, e, s;

765:       DMPlexGetConeSize(dm, oldp, &coneSize);
766:       DMPlexGetCone(dm, oldp, &cone);
767:       DMPlexGetConeOrientation(dm, oldp, &ornt);
768:       DMPlexGetSupportSize(dm, oldp, &supportSize);
769:       DMPlexGetSupport(dm, oldp, &support);
770:       if (dep == depth-1) {
771:         const PetscInt  hybcell = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
772:         const PetscInt *supportF;

774:         /* Split face:       copy in old face to new face to start */
775:         DMPlexGetSupport(sdm, newp,  &supportF);
776:         DMPlexSetSupport(sdm, splitp, supportF);
777:         /* Split old face:   old vertices/edges in cone so no change */
778:         /* Split new face:   new vertices/edges in cone */
779:         for (q = 0; q < coneSize; ++q) {
780:           PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v);
781:           if (v < 0) {
782:             PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
783:             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);
784:             coneNew[2+q] = DMPlexShiftPoint_Internal(cone[q], depth, depthMax, depthEnd, depthShift) /*cone[q] + depthOffset[dep-1]*/;
785:           } else {
786:             coneNew[2+q] = v + pMaxNew[dep-1];
787:           }
788:         }
789:         DMPlexSetCone(sdm, splitp, &coneNew[2]);
790:         DMPlexSetConeOrientation(sdm, splitp, ornt);
791:         /* Face support */
792:         for (s = 0; s < supportSize; ++s) {
793:           PetscInt val;

795:           DMLabelGetValue(label, support[s], &val);
796:           if (val < 0) {
797:             /* Split old face:   Replace negative side cell with cohesive cell */
798:              DMPlexInsertSupport(sdm, newp, s, hybcell);
799:           } else {
800:             /* Split new face:   Replace positive side cell with cohesive cell */
801:             DMPlexInsertSupport(sdm, splitp, s, hybcell);
802:             /* Get orientation for cohesive face */
803:             {
804:               const PetscInt *ncone, *nconeO;
805:               PetscInt        nconeSize, nc;

807:               DMPlexGetConeSize(dm, support[s], &nconeSize);
808:               DMPlexGetCone(dm, support[s], &ncone);
809:               DMPlexGetConeOrientation(dm, support[s], &nconeO);
810:               for (nc = 0; nc < nconeSize; ++nc) {
811:                 if (ncone[nc] == oldp) {
812:                   coneONew[0] = nconeO[nc];
813:                   break;
814:                 }
815:               }
816:               if (nc >= nconeSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate face %d in neighboring cell %d", oldp, support[s]);
817:             }
818:           }
819:         }
820:         /* Cohesive cell:    Old and new split face, then new cohesive faces */
821:         coneNew[0]  = newp;   /* Extracted negative side orientation above */
822:         coneNew[1]  = splitp;
823:         coneONew[1] = coneONew[0];
824:         for (q = 0; q < coneSize; ++q) {
825:           PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v);
826:           if (v < 0) {
827:             PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
828:             coneNew[2+q]  = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
829:             coneONew[2+q] = 0;
830:           } else {
831:             coneNew[2+q]  = v + pMaxNew[dep] + numSplitPoints[dep];
832:           }
833:           coneONew[2+q] = 0;
834:         }
835:         DMPlexSetCone(sdm, hybcell, coneNew);
836:         DMPlexSetConeOrientation(sdm, hybcell, coneONew);
837:       } else if (dep == 0) {
838:         const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1];

840:         /* Split old vertex: Edges in old split faces and new cohesive edge */
841:         for (e = 0, qn = 0; e < supportSize; ++e) {
842:           PetscInt val;

844:           DMLabelGetValue(label, support[e], &val);
845:           if ((val == 1) || (val == (shift + 1))) {
846:             supportNew[qn++] = DMPlexShiftPoint_Internal(support[e], depth, depthMax, depthEnd, depthShift) /*support[e] + depthOffset[dep+1]*/;
847:           }
848:         }
849:         supportNew[qn] = hybedge;
850:         DMPlexSetSupport(sdm, newp, supportNew);
851:         /* Split new vertex: Edges in new split faces and new cohesive edge */
852:         for (e = 0, qp = 0; e < supportSize; ++e) {
853:           PetscInt val, edge;

855:           DMLabelGetValue(label, support[e], &val);
856:           if (val == 1) {
857:             PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge);
858:             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
859:             supportNew[qp++] = edge + pMaxNew[dep+1];
860:           } else if (val == -(shift + 1)) {
861:             supportNew[qp++] = DMPlexShiftPoint_Internal(support[e], depth, depthMax, depthEnd, depthShift) /*support[e] + depthOffset[dep+1]*/;
862:           }
863:         }
864:         supportNew[qp] = hybedge;
865:         DMPlexSetSupport(sdm, splitp, supportNew);
866:         /* Hybrid edge:    Old and new split vertex */
867:         coneNew[0] = newp;
868:         coneNew[1] = splitp;
869:         DMPlexSetCone(sdm, hybedge, coneNew);
870:         for (e = 0, qf = 0; e < supportSize; ++e) {
871:           PetscInt val, edge;

873:           DMLabelGetValue(label, support[e], &val);
874:           if (val == 1) {
875:             PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge);
876:             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
877:             supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2];
878:           }
879:         }
880:         DMPlexSetSupport(sdm, hybedge, supportNew);
881:       } else if (dep == dim-2) {
882:         const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1];

884:         /* Split old edge:   old vertices in cone so no change */
885:         /* Split new edge:   new vertices in cone */
886:         for (q = 0; q < coneSize; ++q) {
887:           PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v);
888:           if (v < 0) {
889:             PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
890:             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);
891:             coneNew[q] = DMPlexShiftPoint_Internal(cone[q], depth, depthMax, depthEnd, depthShift) /*cone[q] + depthOffset[dep-1]*/;
892:           } else {
893:             coneNew[q] = v + pMaxNew[dep-1];
894:           }
895:         }
896:         DMPlexSetCone(sdm, splitp, coneNew);
897:         /* Split old edge: Faces in positive side cells and old split faces */
898:         for (e = 0, q = 0; e < supportSize; ++e) {
899:           PetscInt val;

901:           DMLabelGetValue(label, support[e], &val);
902:           if (val == dim-1) {
903:             supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthMax, depthEnd, depthShift) /*support[e] + depthOffset[dep+1]*/;
904:           } else if (val == (shift + dim-1)) {
905:             supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthMax, depthEnd, depthShift) /*support[e] + depthOffset[dep+1]*/;
906:           }
907:         }
908:         supportNew[q++] = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
909:         DMPlexSetSupport(sdm, newp, supportNew);
910:         /* Split new edge: Faces in negative side cells and new split faces */
911:         for (e = 0, q = 0; e < supportSize; ++e) {
912:           PetscInt val, face;

914:           DMLabelGetValue(label, support[e], &val);
915:           if (val == dim-1) {
916:             PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &face);
917:             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
918:             supportNew[q++] = face + pMaxNew[dep+1];
919:           } else if (val == -(shift + dim-1)) {
920:             supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthMax, depthEnd, depthShift) /*support[e] + depthOffset[dep+1]*/;
921:           }
922:         }
923:         supportNew[q++] = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
924:         DMPlexSetSupport(sdm, splitp, supportNew);
925:         /* Hybrid face */
926:         coneNew[0] = newp;
927:         coneNew[1] = splitp;
928:         for (v = 0; v < coneSize; ++v) {
929:           PetscInt vertex;
930:           PetscFindInt(cone[v], numSplitPoints[dep-1], splitPoints[dep-1], &vertex);
931:           if (vertex < 0) {
932:             PetscFindInt(cone[v], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &vertex);
933:             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);
934:             coneNew[2+v] = vertex + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
935:           } else {
936:             coneNew[2+v] = vertex + pMaxNew[dep] + numSplitPoints[dep];
937:           }
938:         }
939:         DMPlexSetCone(sdm, hybface, coneNew);
940:         for (e = 0, qf = 0; e < supportSize; ++e) {
941:           PetscInt val, face;

943:           DMLabelGetValue(label, support[e], &val);
944:           if (val == dim-1) {
945:             PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &face);
946:             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
947:             supportNew[qf++] = face + pMaxNew[dep+2] + numSplitPoints[dep+2];
948:           }
949:         }
950:         DMPlexSetSupport(sdm, hybface, supportNew);
951:       }
952:     }
953:   }
954:   for (dep = 0; dep <= depth; ++dep) {
955:     for (p = 0; p < numUnsplitPoints[dep]; ++p) {
956:       const PetscInt  oldp   = unsplitPoints[dep][p];
957:       const PetscInt  newp   = DMPlexShiftPoint_Internal(oldp, depth, depthMax, depthEnd, depthShift) /*oldp + depthOffset[dep]*/;
958:       const PetscInt *cone, *support, *ornt;
959:       PetscInt        coneSize, supportSize, supportSizeNew, q, qf, e, f, s;

961:       DMPlexGetConeSize(dm, oldp, &coneSize);
962:       DMPlexGetCone(dm, oldp, &cone);
963:       DMPlexGetConeOrientation(dm, oldp, &ornt);
964:       DMPlexGetSupportSize(dm, oldp, &supportSize);
965:       DMPlexGetSupport(dm, oldp, &support);
966:       if (dep == 0) {
967:         const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];

969:         /* Unsplit vertex */
970:         DMPlexGetSupportSize(sdm, newp, &supportSizeNew);
971:         for (s = 0, q = 0; s < supportSize; ++s) {
972:           supportNew[q++] = DMPlexShiftPoint_Internal(support[s], depth, depthMax, depthEnd, depthShift) /*support[s] + depthOffset[dep+1]*/;
973:           PetscFindInt(support[s], numSplitPoints[dep+1], splitPoints[dep+1], &e);
974:           if (e >= 0) {
975:             supportNew[q++] = e + pMaxNew[dep+1];
976:           }
977:         }
978:         supportNew[q++] = hybedge;
979:         supportNew[q++] = hybedge;
980:         if (q != supportSizeNew) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Support size %d != %d for vertex %d", q, supportSizeNew, newp);
981:         DMPlexSetSupport(sdm, newp, supportNew);
982:         /* Hybrid edge */
983:         coneNew[0] = newp;
984:         coneNew[1] = newp;
985:         DMPlexSetCone(sdm, hybedge, coneNew);
986:         for (e = 0, qf = 0; e < supportSize; ++e) {
987:           PetscInt val, edge;

989:           DMLabelGetValue(label, support[e], &val);
990:           if (val == 1) {
991:             PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge);
992:             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
993:             supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2];
994:           } else if  (val ==  (shift2 + 1)) {
995:             PetscFindInt(support[e], numUnsplitPoints[dep+1], unsplitPoints[dep+1], &edge);
996:             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a unsplit edge", support[e]);
997:             supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2] + numSplitPoints[dep+1];
998:           }
999:         }
1000:         DMPlexSetSupport(sdm, hybedge, supportNew);
1001:       } else if (dep == dim-2) {
1002:         const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep];
1003:         PetscInt       hybcell = -1;

1005:         /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */
1006:         for (f = 0, qf = 0; f < supportSize; ++f) {
1007:           PetscInt val, face;

1009:           DMLabelGetValue(label, support[f], &val);
1010:           if (val == dim-1) {
1011:             PetscFindInt(support[f], numSplitPoints[dep+1], splitPoints[dep+1], &face);
1012:             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[f]);
1013:             supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthMax, depthEnd, depthShift) /*support[f] + depthOffset[dep+1]*/;
1014:             supportNew[qf++] = face + pMaxNew[dep+1];
1015:             hybcell          = face + pMaxNew[dep+2] + numSplitPoints[dep+2];
1016:           } else {
1017:             supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthMax, depthEnd, depthShift) /*support[f] + depthOffset[dep+1]*/;
1018:           }
1019:         }
1020:         supportNew[qf++] = hybface;
1021:         supportNew[qf++] = hybface;
1022:         DMPlexSetSupport(sdm, newp, supportNew);
1023:         /* Add hybrid face */
1024:         coneNew[0] = newp;
1025:         PetscFindInt(cone[0], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1026:         if (v < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex %d is not an unsplit vertex", cone[0]);
1027:         coneNew[1] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
1028:         coneNew[2] = newp;
1029:         PetscFindInt(cone[1], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v);
1030:         if (v < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex %d is not an unsplit vertex", cone[1]);
1031:         coneNew[3] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1];
1032:         DMPlexSetCone(sdm, hybface, coneNew);
1033:         supportNew[0] = hybcell;
1034:         DMPlexSetSupport(sdm, hybface, supportNew);
1035:       }
1036:     }
1037:   }
1038:   /* Step 6b: Replace split points in negative side cones */
1039:   for (sp = 0; sp < numSP; ++sp) {
1040:     PetscInt        dep = values[sp];
1041:     IS              pIS;
1042:     PetscInt        numPoints;
1043:     const PetscInt *points;

1045:     if (dep >= 0) continue;
1046:     DMLabelGetStratumIS(label, dep, &pIS);
1047:     if (!pIS) continue;
1048:     dep  = -dep - shift;
1049:     ISGetLocalSize(pIS, &numPoints);
1050:     ISGetIndices(pIS, &points);
1051:     for (p = 0; p < numPoints; ++p) {
1052:       const PetscInt  oldp = points[p];
1053:       const PetscInt  newp = DMPlexShiftPoint_Internal(oldp, depth, depthMax, depthEnd, depthShift) /*depthOffset[dep] + oldp*/;
1054:       const PetscInt *cone;
1055:       PetscInt        coneSize, c;
1056:       /* PetscBool       replaced = PETSC_FALSE; */

1058:       /* Negative edge: replace split vertex */
1059:       /* Negative cell: replace split face */
1060:       DMPlexGetConeSize(sdm, newp, &coneSize);
1061:       DMPlexGetCone(sdm, newp, &cone);
1062:       for (c = 0; c < coneSize; ++c) {
1063:         const PetscInt coldp = cone[c] - depthOffset[dep-1];
1064:         PetscInt       csplitp, cp, val;

1066:         DMLabelGetValue(label, coldp, &val);
1067:         if (val == dep-1) {
1068:           PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);
1069:           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
1070:           csplitp  = pMaxNew[dep-1] + cp;
1071:           DMPlexInsertCone(sdm, newp, c, csplitp);
1072:           /* replaced = PETSC_TRUE; */
1073:         }
1074:       }
1075:       /* Cells with only a vertex or edge on the submesh have no replacement */
1076:       /* if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp); */
1077:     }
1078:     ISRestoreIndices(pIS, &points);
1079:     ISDestroy(&pIS);
1080:   }
1081:   /* Step 7: Stratify */
1082:   DMPlexStratify(sdm);
1083:   /* Step 8: Coordinates */
1084:   DMPlexShiftCoordinates_Internal(dm, depthShift, sdm);
1085:   DMGetCoordinateSection(sdm, &coordSection);
1086:   DMGetCoordinatesLocal(sdm, &coordinates);
1087:   VecGetArray(coordinates, &coords);
1088:   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
1089:     const PetscInt newp   = DMPlexShiftPoint_Internal(splitPoints[0][v], depth, depthMax, depthEnd, depthShift) /*depthOffset[0] + splitPoints[0][v]*/;
1090:     const PetscInt splitp = pMaxNew[0] + v;
1091:     PetscInt       dof, off, soff, d;

1093:     PetscSectionGetDof(coordSection, newp, &dof);
1094:     PetscSectionGetOffset(coordSection, newp, &off);
1095:     PetscSectionGetOffset(coordSection, splitp, &soff);
1096:     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
1097:   }
1098:   VecRestoreArray(coordinates, &coords);
1099:   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
1100:   DMPlexShiftSF_Internal(dm, depthShift, sdm);
1101:   /* Step 10: Labels */
1102:   DMPlexShiftLabels_Internal(dm, depthShift, sdm);
1103:   DMPlexGetNumLabels(sdm, &numLabels);
1104:   for (dep = 0; dep <= depth; ++dep) {
1105:     for (p = 0; p < numSplitPoints[dep]; ++p) {
1106:       const PetscInt newp   = DMPlexShiftPoint_Internal(splitPoints[dep][p], depth, depthMax, depthEnd, depthShift) /*depthOffset[dep] + splitPoints[dep][p]*/;
1107:       const PetscInt splitp = pMaxNew[dep] + p;
1108:       PetscInt       l;

1110:       for (l = 0; l < numLabels; ++l) {
1111:         DMLabel     mlabel;
1112:         const char *lname;
1113:         PetscInt    val;
1114:         PetscBool   isDepth;

1116:         DMPlexGetLabelName(sdm, l, &lname);
1117:         PetscStrcmp(lname, "depth", &isDepth);
1118:         if (isDepth) continue;
1119:         DMPlexGetLabel(sdm, lname, &mlabel);
1120:         DMLabelGetValue(mlabel, newp, &val);
1121:         if (val >= 0) {
1122:           DMLabelSetValue(mlabel, splitp, val);
1123: #if 0
1124:           /* Do not put cohesive edges into the label */
1125:           if (dep == 0) {
1126:             const PetscInt cedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1127:             DMLabelSetValue(mlabel, cedge, val);
1128:           } else if (dep == dim-2) {
1129:             const PetscInt cface = p + pMaxNew[dep+1] + numSplitPoints[dep+1];
1130:             DMLabelSetValue(mlabel, cface, val);
1131:           }
1132:           /* Do not put cohesive faces into the label */
1133: #endif
1134:         }
1135:       }
1136:     }
1137:   }
1138:   for (sp = 0; sp < numSP; ++sp) {
1139:     const PetscInt dep = values[sp];

1141:     if ((dep < 0) || (dep > depth)) continue;
1142:     if (splitIS[dep]) {ISRestoreIndices(splitIS[dep], &splitPoints[dep]);}
1143:     ISDestroy(&splitIS[dep]);
1144:     if (unsplitIS[dep]) {ISRestoreIndices(unsplitIS[dep], &unsplitPoints[dep]);}
1145:     ISDestroy(&unsplitIS[dep]);
1146:   }
1147:   if (label) {
1148:     ISRestoreIndices(valueIS, &values);
1149:     ISDestroy(&valueIS);
1150:   }
1151:   for (d = 0; d <= depth; ++d) {
1152:     DMPlexGetDepthStratum(sdm, d, NULL, &pEnd);
1153:     pMaxNew[d] = pEnd - numHybridPoints[d] - numHybridPointsOld[d];
1154:   }
1155:   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);
1156:   PetscFree3(coneNew, coneONew, supportNew);
1157:   PetscFree6(depthMax, depthEnd, depthShift, depthOffset, pMaxNew, numHybridPointsOld);
1158:   PetscFree7(splitIS, unsplitIS, numSplitPoints, numUnsplitPoints, numHybridPoints, splitPoints, unsplitPoints);
1159:   return(0);
1160: }

1164: /*@C
1165:   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface

1167:   Collective on dm

1169:   Input Parameters:
1170: + dm - The original DM
1171: - label - The label specifying the boundary faces (this could be auto-generated)

1173:   Output Parameters:
1174: - dmSplit - The new DM

1176:   Level: developer

1178: .seealso: DMCreate(), DMPlexLabelCohesiveComplete()
1179: @*/
1180: PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
1181: {
1182:   DM             sdm;
1183:   PetscInt       dim;

1189:   DMCreate(PetscObjectComm((PetscObject)dm), &sdm);
1190:   DMSetType(sdm, DMPLEX);
1191:   DMPlexGetDimension(dm, &dim);
1192:   DMPlexSetDimension(sdm, dim);
1193:   switch (dim) {
1194:   case 2:
1195:   case 3:
1196:     DMPlexConstructCohesiveCells_Internal(dm, label, sdm);
1197:     break;
1198:   default:
1199:     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
1200:   }
1201:   *dmSplit = sdm;
1202:   return(0);
1203: }

1207: /*@
1208:   DMPlexLabelCohesiveComplete - Starting with a label marking vertices on an internal surface, we add all other mesh pieces
1209:   to complete the surface

1211:   Input Parameters:
1212: + dm - The DM
1213: . label - A DMLabel marking the surface vertices
1214: . flip  - Flag to flip the submesh normal and replace points on the other side
1215: - subdm - The subDM associated with the label, or NULL

1217:   Output Parameter:
1218: . label - A DMLabel marking all surface points

1220:   Level: developer

1222: .seealso: DMPlexConstructCohesiveCells(), DMPlexLabelComplete()
1223: @*/
1224: PetscErrorCode DMPlexLabelCohesiveComplete(DM dm, DMLabel label, PetscBool flip, DM subdm)
1225: {
1226:   DMLabel         depthLabel;
1227:   IS              dimIS, subpointIS, facePosIS, faceNegIS;
1228:   const PetscInt *points, *subpoints;
1229:   const PetscInt  rev   = flip ? -1 : 1;
1230:   PetscInt        shift = 100, shift2 = 200, dim, dep, cStart, cEnd, numPoints, numSubpoints, p, val;
1231:   PetscErrorCode  ierr;

1234:   DMPlexGetDepthLabel(dm, &depthLabel);
1235:   DMPlexGetDimension(dm, &dim);
1236:   if (subdm) {
1237:     DMPlexCreateSubpointIS(subdm, &subpointIS);
1238:     if (subpointIS) {
1239:       ISGetLocalSize(subpointIS, &numSubpoints);
1240:       ISGetIndices(subpointIS, &subpoints);
1241:     }
1242:   }
1243:   /* Mark cell on the fault, and its faces which touch the fault: cell orientation for face gives the side of the fault */
1244:   DMLabelGetStratumIS(label, dim-1, &dimIS);
1245:   if (!dimIS) return(0);
1246:   ISGetLocalSize(dimIS, &numPoints);
1247:   ISGetIndices(dimIS, &points);
1248:   for (p = 0; p < numPoints; ++p) { /* Loop over fault faces */
1249:     const PetscInt *support;
1250:     PetscInt        supportSize, s;

1252:     DMPlexGetSupportSize(dm, points[p], &supportSize);
1253:     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
1254:     DMPlexGetSupport(dm, points[p], &support);
1255:     for (s = 0; s < supportSize; ++s) {
1256:       const PetscInt *cone, *ornt;
1257:       PetscInt        coneSize, c;
1258:       PetscBool       pos = PETSC_TRUE;

1260:       DMPlexGetConeSize(dm, support[s], &coneSize);
1261:       DMPlexGetCone(dm, support[s], &cone);
1262:       DMPlexGetConeOrientation(dm, support[s], &ornt);
1263:       for (c = 0; c < coneSize; ++c) {
1264:         if (cone[c] == points[p]) {
1265:           PetscInt o = ornt[c];

1267:           if (subdm) {
1268:             const PetscInt *subcone, *subornt;
1269:             PetscInt        subpoint, subface, subconeSize, sc;

1271:             PetscFindInt(support[s], numSubpoints, subpoints, &subpoint);
1272:             PetscFindInt(points[p],  numSubpoints, subpoints, &subface);
1273:             DMPlexGetConeSize(subdm, subpoint, &subconeSize);
1274:             DMPlexGetCone(subdm, subpoint, &subcone);
1275:             DMPlexGetConeOrientation(subdm, subpoint, &subornt);
1276:             for (sc = 0; sc < subconeSize; ++sc) {
1277:               if (subcone[sc] == subface) {
1278:                 o = subornt[0];
1279:                 break;
1280:               }
1281:             }
1282:             if (sc >= subconeSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find point %d in cone for subpoint %d", points[p], subpoint);
1283:           }
1284:           if (o >= 0) {
1285:             DMLabelSetValue(label, support[s],  rev*(shift+dim));
1286:             pos  = rev > 0 ? PETSC_TRUE : PETSC_FALSE;
1287:           } else {
1288:             DMLabelSetValue(label, support[s], -rev*(shift+dim));
1289:             pos  = rev > 0 ? PETSC_FALSE : PETSC_TRUE;
1290:           }
1291:           break;
1292:         }
1293:       }
1294:       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
1295:       /* Put faces touching the fault in the label */
1296:       for (c = 0; c < coneSize; ++c) {
1297:         const PetscInt point = cone[c];

1299:         DMLabelGetValue(label, point, &val);
1300:         if (val == -1) {
1301:           PetscInt *closure = NULL;
1302:           PetscInt  closureSize, cl;

1304:           DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1305:           for (cl = 0; cl < closureSize*2; cl += 2) {
1306:             const PetscInt clp = closure[cl];

1308:             DMLabelGetValue(label, clp, &val);
1309:             if ((val >= 0) && (val < dim-1)) {
1310:               DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));
1311:               break;
1312:             }
1313:           }
1314:           DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1315:         }
1316:       }
1317:     }
1318:   }
1319:   if (subdm) {
1320:     if (subpointIS) {ISRestoreIndices(subpointIS, &subpoints);}
1321:     ISDestroy(&subpointIS);
1322:   }
1323:   ISRestoreIndices(dimIS, &points);
1324:   ISDestroy(&dimIS);
1325:   /* Search for other cells/faces/edges connected to the fault by a vertex */
1326:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1327:   DMLabelGetStratumIS(label, 0, &dimIS);
1328:   if (!dimIS) return(0);
1329:   ISGetLocalSize(dimIS, &numPoints);
1330:   ISGetIndices(dimIS, &points);
1331:   for (p = 0; p < numPoints; ++p) { /* Loop over fault vertices */
1332:     PetscInt *star = NULL;
1333:     PetscInt  starSize, s;
1334:     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */

1336:     /* All points connected to the fault are inside a cell, so at the top level we will only check cells */
1337:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);
1338:     while (again) {
1339:       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
1340:       again = 0;
1341:       for (s = 0; s < starSize*2; s += 2) {
1342:         const PetscInt  point = star[s];
1343:         const PetscInt *cone;
1344:         PetscInt        coneSize, c;

1346:         if ((point < cStart) || (point >= cEnd)) continue;
1347:         DMLabelGetValue(label, point, &val);
1348:         if (val != -1) continue;
1349:         again = again == 1 ? 1 : 2;
1350:         DMPlexGetConeSize(dm, point, &coneSize);
1351:         DMPlexGetCone(dm, point, &cone);
1352:         for (c = 0; c < coneSize; ++c) {
1353:           DMLabelGetValue(label, cone[c], &val);
1354:           if (val != -1) {
1355:             const PetscInt *ccone;
1356:             PetscInt        cconeSize, cc, side;

1358:             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
1359:             if (val > 0) side =  1;
1360:             else         side = -1;
1361:             DMLabelSetValue(label, point, side*(shift+dim));
1362:             /* Mark cell faces which touch the fault */
1363:             DMPlexGetConeSize(dm, point, &cconeSize);
1364:             DMPlexGetCone(dm, point, &ccone);
1365:             for (cc = 0; cc < cconeSize; ++cc) {
1366:               PetscInt *closure = NULL;
1367:               PetscInt  closureSize, cl;

1369:               DMLabelGetValue(label, ccone[cc], &val);
1370:               if (val != -1) continue;
1371:               DMPlexGetTransitiveClosure(dm, ccone[cc], PETSC_TRUE, &closureSize, &closure);
1372:               for (cl = 0; cl < closureSize*2; cl += 2) {
1373:                 const PetscInt clp = closure[cl];

1375:                 DMLabelGetValue(label, clp, &val);
1376:                 if (val == -1) continue;
1377:                 DMLabelSetValue(label, ccone[cc], side*(shift+dim-1));
1378:                 break;
1379:               }
1380:               DMPlexRestoreTransitiveClosure(dm, ccone[cc], PETSC_TRUE, &closureSize, &closure);
1381:             }
1382:             again = 1;
1383:             break;
1384:           }
1385:         }
1386:       }
1387:     }
1388:     /* Classify the rest by cell membership */
1389:     for (s = 0; s < starSize*2; s += 2) {
1390:       const PetscInt point = star[s];

1392:       DMLabelGetValue(label, point, &val);
1393:       if (val == -1) {
1394:         PetscInt  *sstar = NULL;
1395:         PetscInt   sstarSize, ss;
1396:         PetscBool  marked = PETSC_FALSE;

1398:         DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);
1399:         for (ss = 0; ss < sstarSize*2; ss += 2) {
1400:           const PetscInt spoint = sstar[ss];

1402:           if ((spoint < cStart) || (spoint >= cEnd)) continue;
1403:           DMLabelGetValue(label, spoint, &val);
1404:           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
1405:           DMLabelGetValue(depthLabel, point, &dep);
1406:           if (val > 0) {
1407:             DMLabelSetValue(label, point,   shift+dep);
1408:           } else {
1409:             DMLabelSetValue(label, point, -(shift+dep));
1410:           }
1411:           marked = PETSC_TRUE;
1412:           break;
1413:         }
1414:         DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);
1415:         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
1416:       }
1417:     }
1418:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);
1419:   }
1420:   ISRestoreIndices(dimIS, &points);
1421:   ISDestroy(&dimIS);
1422:   /* If any faces touching the fault divide cells on either side, split them */
1423:   DMLabelGetStratumIS(label,   shift+dim-1,  &facePosIS);
1424:   DMLabelGetStratumIS(label, -(shift+dim-1), &faceNegIS);
1425:   ISExpand(facePosIS, faceNegIS, &dimIS);
1426:   ISDestroy(&facePosIS);
1427:   ISDestroy(&faceNegIS);
1428:   ISGetLocalSize(dimIS, &numPoints);
1429:   ISGetIndices(dimIS, &points);
1430:   for (p = 0; p < numPoints; ++p) {
1431:     const PetscInt  point = points[p];
1432:     const PetscInt *support;
1433:     PetscInt        supportSize, valA, valB;

1435:     DMPlexGetSupportSize(dm, point, &supportSize);
1436:     if (supportSize != 2) continue;
1437:     DMPlexGetSupport(dm, point, &support);
1438:     DMLabelGetValue(label, support[0], &valA);
1439:     DMLabelGetValue(label, support[1], &valB);
1440:     if ((valA == -1) || (valB == -1)) continue;
1441:     if (valA*valB > 0) continue;
1442:     /* Split the face */
1443:     DMLabelGetValue(label, point, &valA);
1444:     DMLabelClearValue(label, point, valA);
1445:     DMLabelSetValue(label, point, dim-1);
1446:     /* Label its closure:
1447:       unmarked: label as unsplit
1448:       incident: relabel as split
1449:       split:    do nothing
1450:     */
1451:     {
1452:       PetscInt *closure = NULL;
1453:       PetscInt  closureSize, cl;

1455:       DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1456:       for (cl = 0; cl < closureSize*2; cl += 2) {
1457:         DMLabelGetValue(label, closure[cl], &valA);
1458:         if (valA < 0) { /* Mark as unsplit */
1459:           DMLabelGetValue(depthLabel, closure[cl], &dep);
1460:           DMLabelSetValue(label, closure[cl], shift2+dep);
1461:         } else if (valA >= shift) {
1462:           DMLabelGetValue(depthLabel, closure[cl], &dep);
1463:           DMLabelClearValue(label, closure[cl], valA);
1464:           DMLabelSetValue(label, closure[cl], dep);
1465:         }
1466:       }
1467:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
1468:     }
1469:   }
1470:   ISRestoreIndices(dimIS, &points);
1471:   ISDestroy(&dimIS);
1472:   return(0);
1473: }

1477: /*@C
1478:   DMPlexCreateHybridMesh - Create a mesh with hybrid cells along an internal interface

1480:   Collective on dm

1482:   Input Parameters:
1483: + dm - The original DM
1484: - labelName - The label specifying the interface vertices

1486:   Output Parameters:
1487: + hybridLabel - The label fully marking the interface
1488: - dmHybrid - The new DM

1490:   Level: developer

1492: .seealso: DMPlexConstructCohesiveCells(), DMPlexLabelCohesiveComplete(), DMCreate()
1493: @*/
1494: PetscErrorCode DMPlexCreateHybridMesh(DM dm, DMLabel label, DMLabel *hybridLabel, DM *dmHybrid)
1495: {
1496:   DM             idm;
1497:   DMLabel        subpointMap, hlabel;
1498:   PetscInt       dim;

1505:   DMPlexGetDimension(dm, &dim);
1506:   DMPlexCreateSubmesh(dm, label, 1, &idm);
1507:   DMPlexOrient(idm);
1508:   DMPlexGetSubpointMap(idm, &subpointMap);
1509:   DMLabelDuplicate(subpointMap, &hlabel);
1510:   DMLabelClearStratum(hlabel, dim);
1511:   DMPlexLabelCohesiveComplete(dm, hlabel, PETSC_FALSE, idm);
1512:   DMDestroy(&idm);
1513:   DMPlexConstructCohesiveCells(dm, hlabel, dmHybrid);
1514:   if (hybridLabel) *hybridLabel = hlabel;
1515:   else             {DMLabelDestroy(&hlabel);}
1516:   return(0);
1517: }

1521: /* Here we need the explicit assumption that:

1523:      For any marked cell, the marked vertices constitute a single face
1524: */
1525: static PetscErrorCode DMPlexMarkSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, DM subdm)
1526: {
1527:   IS               subvertexIS = NULL;
1528:   const PetscInt  *subvertices;
1529:   PetscInt        *pStart, *pEnd, *pMax, pSize;
1530:   PetscInt         depth, dim, d, numSubVerticesInitial = 0, v;
1531:   PetscErrorCode   ierr;

1534:   *numFaces = 0;
1535:   *nFV      = 0;
1536:   DMPlexGetDepth(dm, &depth);
1537:   DMPlexGetDimension(dm, &dim);
1538:   pSize = PetscMax(depth, dim) + 1;
1539:   PetscMalloc3(pSize,&pStart,pSize,&pEnd,pSize,&pMax);
1540:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
1541:   for (d = 0; d <= depth; ++d) {
1542:     DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);
1543:     if (pMax[d] >= 0) pEnd[d] = PetscMin(pEnd[d], pMax[d]);
1544:   }
1545:   /* Loop over initial vertices and mark all faces in the collective star() */
1546:   if (vertexLabel) {DMLabelGetStratumIS(vertexLabel, value, &subvertexIS);}
1547:   if (subvertexIS) {
1548:     ISGetSize(subvertexIS, &numSubVerticesInitial);
1549:     ISGetIndices(subvertexIS, &subvertices);
1550:   }
1551:   for (v = 0; v < numSubVerticesInitial; ++v) {
1552:     const PetscInt vertex = subvertices[v];
1553:     PetscInt      *star   = NULL;
1554:     PetscInt       starSize, s, numCells = 0, c;

1556:     DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
1557:     for (s = 0; s < starSize*2; s += 2) {
1558:       const PetscInt point = star[s];
1559:       if ((point >= pStart[depth]) && (point < pEnd[depth])) star[numCells++] = point;
1560:     }
1561:     for (c = 0; c < numCells; ++c) {
1562:       const PetscInt cell    = star[c];
1563:       PetscInt      *closure = NULL;
1564:       PetscInt       closureSize, cl;
1565:       PetscInt       cellLoc, numCorners = 0, faceSize = 0;

1567:       DMLabelGetValue(subpointMap, cell, &cellLoc);
1568:       if (cellLoc == 2) continue;
1569:       if (cellLoc >= 0) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d has dimension %d in the surface label", cell, cellLoc);
1570:       DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
1571:       for (cl = 0; cl < closureSize*2; cl += 2) {
1572:         const PetscInt point = closure[cl];
1573:         PetscInt       vertexLoc;

1575:         if ((point >= pStart[0]) && (point < pEnd[0])) {
1576:           ++numCorners;
1577:           DMLabelGetValue(vertexLabel, point, &vertexLoc);
1578:           if (vertexLoc == value) closure[faceSize++] = point;
1579:         }
1580:       }
1581:       if (!(*nFV)) {DMPlexGetNumFaceVertices(dm, dim, numCorners, nFV);}
1582:       if (faceSize > *nFV) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
1583:       if (faceSize == *nFV) {
1584:         const PetscInt *cells = NULL;
1585:         PetscInt        numCells, nc;

1587:         ++(*numFaces);
1588:         for (cl = 0; cl < faceSize; ++cl) {
1589:           DMLabelSetValue(subpointMap, closure[cl], 0);
1590:         }
1591:         DMPlexGetJoin(dm, faceSize, closure, &numCells, &cells);
1592:         for (nc = 0; nc < numCells; ++nc) {
1593:           DMLabelSetValue(subpointMap, cells[nc], 2);
1594:         }
1595:         DMPlexRestoreJoin(dm, faceSize, closure, &numCells, &cells);
1596:       }
1597:       DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
1598:     }
1599:     DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
1600:   }
1601:   if (subvertexIS) {
1602:     ISRestoreIndices(subvertexIS, &subvertices);
1603:   }
1604:   ISDestroy(&subvertexIS);
1605:   PetscFree3(pStart,pEnd,pMax);
1606:   return(0);
1607: }

1611: static PetscErrorCode DMPlexMarkSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, DM subdm)
1612: {
1613:   IS               subvertexIS;
1614:   const PetscInt  *subvertices;
1615:   PetscInt        *pStart, *pEnd, *pMax;
1616:   PetscInt         dim, d, numSubVerticesInitial = 0, v;
1617:   PetscErrorCode   ierr;

1620:   DMPlexGetDimension(dm, &dim);
1621:   PetscMalloc3(dim+1,&pStart,dim+1,&pEnd,dim+1,&pMax);
1622:   DMPlexGetHybridBounds(dm, &pMax[dim], dim>1 ? &pMax[dim-1] : NULL, dim > 2 ? &pMax[1] : NULL, &pMax[0]);
1623:   for (d = 0; d <= dim; ++d) {
1624:     DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);
1625:     if (pMax[d] >= 0) pEnd[d] = PetscMin(pEnd[d], pMax[d]);
1626:   }
1627:   /* Loop over initial vertices and mark all faces in the collective star() */
1628:   DMLabelGetStratumIS(vertexLabel, value, &subvertexIS);
1629:   if (subvertexIS) {
1630:     ISGetSize(subvertexIS, &numSubVerticesInitial);
1631:     ISGetIndices(subvertexIS, &subvertices);
1632:   }
1633:   for (v = 0; v < numSubVerticesInitial; ++v) {
1634:     const PetscInt vertex = subvertices[v];
1635:     PetscInt      *star   = NULL;
1636:     PetscInt       starSize, s, numFaces = 0, f;

1638:     DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
1639:     for (s = 0; s < starSize*2; s += 2) {
1640:       const PetscInt point = star[s];
1641:       if ((point >= pStart[dim-1]) && (point < pEnd[dim-1])) star[numFaces++] = point;
1642:     }
1643:     for (f = 0; f < numFaces; ++f) {
1644:       const PetscInt face    = star[f];
1645:       PetscInt      *closure = NULL;
1646:       PetscInt       closureSize, c;
1647:       PetscInt       faceLoc;

1649:       DMLabelGetValue(subpointMap, face, &faceLoc);
1650:       if (faceLoc == dim-1) continue;
1651:       if (faceLoc >= 0) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc);
1652:       DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);
1653:       for (c = 0; c < closureSize*2; c += 2) {
1654:         const PetscInt point = closure[c];
1655:         PetscInt       vertexLoc;

1657:         if ((point >= pStart[0]) && (point < pEnd[0])) {
1658:           DMLabelGetValue(vertexLabel, point, &vertexLoc);
1659:           if (vertexLoc != value) break;
1660:         }
1661:       }
1662:       if (c == closureSize*2) {
1663:         const PetscInt *support;
1664:         PetscInt        supportSize, s;

1666:         for (c = 0; c < closureSize*2; c += 2) {
1667:           const PetscInt point = closure[c];

1669:           for (d = 0; d < dim; ++d) {
1670:             if ((point >= pStart[d]) && (point < pEnd[d])) {
1671:               DMLabelSetValue(subpointMap, point, d);
1672:               break;
1673:             }
1674:           }
1675:         }
1676:         DMPlexGetSupportSize(dm, face, &supportSize);
1677:         DMPlexGetSupport(dm, face, &support);
1678:         for (s = 0; s < supportSize; ++s) {
1679:           DMLabelSetValue(subpointMap, support[s], dim);
1680:         }
1681:       }
1682:       DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);
1683:     }
1684:     DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);
1685:   }
1686:   if (subvertexIS) {
1687:     ISRestoreIndices(subvertexIS, &subvertices);
1688:   }
1689:   ISDestroy(&subvertexIS);
1690:   PetscFree3(pStart,pEnd,pMax);
1691:   return(0);
1692: }

1696: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char labelname[], PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, PetscInt *subCells[], DM subdm)
1697: {
1698:   DMLabel         label = NULL;
1699:   const PetscInt *cone;
1700:   PetscInt        dim, cMax, cEnd, c, subc = 0, p, coneSize;
1701:   PetscErrorCode  ierr;

1704:   *numFaces = 0;
1705:   *nFV = 0;
1706:   if (labelname) {DMPlexGetLabel(dm, labelname, &label);}
1707:   *subCells = NULL;
1708:   DMPlexGetDimension(dm, &dim);
1709:   DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
1710:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
1711:   if (cMax < 0) return(0);
1712:   if (label) {
1713:     for (c = cMax; c < cEnd; ++c) {
1714:       PetscInt val;

1716:       DMLabelGetValue(label, c, &val);
1717:       if (val == value) {
1718:         ++(*numFaces);
1719:         DMPlexGetConeSize(dm, c, &coneSize);
1720:       }
1721:     }
1722:   } else {
1723:     *numFaces = cEnd - cMax;
1724:     DMPlexGetConeSize(dm, cMax, &coneSize);
1725:   }
1726:   *nFV = hasLagrange ? coneSize/3 : coneSize/2;
1727:   PetscMalloc1(*numFaces *2, subCells);
1728:   for (c = cMax; c < cEnd; ++c) {
1729:     const PetscInt *cells;
1730:     PetscInt        numCells;

1732:     if (label) {
1733:       PetscInt val;

1735:       DMLabelGetValue(label, c, &val);
1736:       if (val != value) continue;
1737:     }
1738:     DMPlexGetCone(dm, c, &cone);
1739:     for (p = 0; p < *nFV; ++p) {
1740:       DMLabelSetValue(subpointMap, cone[p], 0);
1741:     }
1742:     /* Negative face */
1743:     DMPlexGetJoin(dm, *nFV, cone, &numCells, &cells);
1744:     /* Not true in parallel
1745:     if (numCells != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
1746:     for (p = 0; p < numCells; ++p) {
1747:       DMLabelSetValue(subpointMap, cells[p], 2);
1748:       (*subCells)[subc++] = cells[p];
1749:     }
1750:     DMPlexRestoreJoin(dm, *nFV, cone, &numCells, &cells);
1751:     /* Positive face is not included */
1752:   }
1753:   return(0);
1754: }

1758: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DMLabel subpointMap, DM subdm)
1759: {
1760:   DMLabel        label = NULL;
1761:   PetscInt      *pStart, *pEnd;
1762:   PetscInt       dim, cMax, cEnd, c, d;

1766:   if (labelname) {DMPlexGetLabel(dm, labelname, &label);}
1767:   DMPlexGetDimension(dm, &dim);
1768:   DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
1769:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
1770:   if (cMax < 0) return(0);
1771:   PetscMalloc2(dim+1,&pStart,dim+1,&pEnd);
1772:   for (d = 0; d <= dim; ++d) {DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);}
1773:   for (c = cMax; c < cEnd; ++c) {
1774:     const PetscInt *cone;
1775:     PetscInt       *closure = NULL;
1776:     PetscInt        fconeSize, coneSize, closureSize, cl, val;

1778:     if (label) {
1779:       DMLabelGetValue(label, c, &val);
1780:       if (val != value) continue;
1781:     }
1782:     DMPlexGetConeSize(dm, c, &coneSize);
1783:     DMPlexGetCone(dm, c, &cone);
1784:     DMPlexGetConeSize(dm, cone[0], &fconeSize);
1785:     if (coneSize != (fconeSize ? fconeSize : 1) + 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells");
1786:     /* Negative face */
1787:     DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure);
1788:     for (cl = 0; cl < closureSize*2; cl += 2) {
1789:       const PetscInt point = closure[cl];

1791:       for (d = 0; d <= dim; ++d) {
1792:         if ((point >= pStart[d]) && (point < pEnd[d])) {
1793:           DMLabelSetValue(subpointMap, point, d);
1794:           break;
1795:         }
1796:       }
1797:     }
1798:     DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure);
1799:     /* Cells -- positive face is not included */
1800:     for (cl = 0; cl < 1; ++cl) {
1801:       const PetscInt *support;
1802:       PetscInt        supportSize, s;

1804:       DMPlexGetSupportSize(dm, cone[cl], &supportSize);
1805:       /* if (supportSize != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive faces should separate two cells"); */
1806:       DMPlexGetSupport(dm, cone[cl], &support);
1807:       for (s = 0; s < supportSize; ++s) {
1808:         DMLabelSetValue(subpointMap, support[s], dim);
1809:       }
1810:     }
1811:   }
1812:   PetscFree2(pStart, pEnd);
1813:   return(0);
1814: }

1818: PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
1819: {
1820:   MPI_Comm       comm;
1821:   PetscBool      posOrient = PETSC_FALSE;
1822:   const PetscInt debug     = 0;
1823:   PetscInt       cellDim, faceSize, f;

1827:   PetscObjectGetComm((PetscObject)dm,&comm);
1828:   DMPlexGetDimension(dm, &cellDim);
1829:   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);}

1831:   if (cellDim == 1 && numCorners == 2) {
1832:     /* Triangle */
1833:     faceSize  = numCorners-1;
1834:     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
1835:   } else if (cellDim == 2 && numCorners == 3) {
1836:     /* Triangle */
1837:     faceSize  = numCorners-1;
1838:     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
1839:   } else if (cellDim == 3 && numCorners == 4) {
1840:     /* Tetrahedron */
1841:     faceSize  = numCorners-1;
1842:     posOrient = (oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
1843:   } else if (cellDim == 1 && numCorners == 3) {
1844:     /* Quadratic line */
1845:     faceSize  = 1;
1846:     posOrient = PETSC_TRUE;
1847:   } else if (cellDim == 2 && numCorners == 4) {
1848:     /* Quads */
1849:     faceSize = 2;
1850:     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
1851:       posOrient = PETSC_TRUE;
1852:     } else if ((indices[0] == 3) && (indices[1] == 0)) {
1853:       posOrient = PETSC_TRUE;
1854:     } else {
1855:       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
1856:         posOrient = PETSC_FALSE;
1857:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
1858:     }
1859:   } else if (cellDim == 2 && numCorners == 6) {
1860:     /* Quadratic triangle (I hate this) */
1861:     /* Edges are determined by the first 2 vertices (corners of edges) */
1862:     const PetscInt faceSizeTri = 3;
1863:     PetscInt       sortedIndices[3], i, iFace;
1864:     PetscBool      found                    = PETSC_FALSE;
1865:     PetscInt       faceVerticesTriSorted[9] = {
1866:       0, 3,  4, /* bottom */
1867:       1, 4,  5, /* right */
1868:       2, 3,  5, /* left */
1869:     };
1870:     PetscInt       faceVerticesTri[9] = {
1871:       0, 3,  4, /* bottom */
1872:       1, 4,  5, /* right */
1873:       2, 5,  3, /* left */
1874:     };

1876:     faceSize = faceSizeTri;
1877:     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
1878:     PetscSortInt(faceSizeTri, sortedIndices);
1879:     for (iFace = 0; iFace < 3; ++iFace) {
1880:       const PetscInt ii = iFace*faceSizeTri;
1881:       PetscInt       fVertex, cVertex;

1883:       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
1884:           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
1885:         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
1886:           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
1887:             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
1888:               faceVertices[fVertex] = origVertices[cVertex];
1889:               break;
1890:             }
1891:           }
1892:         }
1893:         found = PETSC_TRUE;
1894:         break;
1895:       }
1896:     }
1897:     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
1898:     if (posOriented) *posOriented = PETSC_TRUE;
1899:     return(0);
1900:   } else if (cellDim == 2 && numCorners == 9) {
1901:     /* Quadratic quad (I hate this) */
1902:     /* Edges are determined by the first 2 vertices (corners of edges) */
1903:     const PetscInt faceSizeQuad = 3;
1904:     PetscInt       sortedIndices[3], i, iFace;
1905:     PetscBool      found                      = PETSC_FALSE;
1906:     PetscInt       faceVerticesQuadSorted[12] = {
1907:       0, 1,  4, /* bottom */
1908:       1, 2,  5, /* right */
1909:       2, 3,  6, /* top */
1910:       0, 3,  7, /* left */
1911:     };
1912:     PetscInt       faceVerticesQuad[12] = {
1913:       0, 1,  4, /* bottom */
1914:       1, 2,  5, /* right */
1915:       2, 3,  6, /* top */
1916:       3, 0,  7, /* left */
1917:     };

1919:     faceSize = faceSizeQuad;
1920:     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
1921:     PetscSortInt(faceSizeQuad, sortedIndices);
1922:     for (iFace = 0; iFace < 4; ++iFace) {
1923:       const PetscInt ii = iFace*faceSizeQuad;
1924:       PetscInt       fVertex, cVertex;

1926:       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
1927:           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
1928:         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
1929:           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
1930:             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
1931:               faceVertices[fVertex] = origVertices[cVertex];
1932:               break;
1933:             }
1934:           }
1935:         }
1936:         found = PETSC_TRUE;
1937:         break;
1938:       }
1939:     }
1940:     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
1941:     if (posOriented) *posOriented = PETSC_TRUE;
1942:     return(0);
1943:   } else if (cellDim == 3 && numCorners == 8) {
1944:     /* Hexes
1945:        A hex is two oriented quads with the normal of the first
1946:        pointing up at the second.

1948:           7---6
1949:          /|  /|
1950:         4---5 |
1951:         | 1-|-2
1952:         |/  |/
1953:         0---3

1955:         Faces are determined by the first 4 vertices (corners of faces) */
1956:     const PetscInt faceSizeHex = 4;
1957:     PetscInt       sortedIndices[4], i, iFace;
1958:     PetscBool      found                     = PETSC_FALSE;
1959:     PetscInt       faceVerticesHexSorted[24] = {
1960:       0, 1, 2, 3,  /* bottom */
1961:       4, 5, 6, 7,  /* top */
1962:       0, 3, 4, 5,  /* front */
1963:       2, 3, 5, 6,  /* right */
1964:       1, 2, 6, 7,  /* back */
1965:       0, 1, 4, 7,  /* left */
1966:     };
1967:     PetscInt       faceVerticesHex[24] = {
1968:       1, 2, 3, 0,  /* bottom */
1969:       4, 5, 6, 7,  /* top */
1970:       0, 3, 5, 4,  /* front */
1971:       3, 2, 6, 5,  /* right */
1972:       2, 1, 7, 6,  /* back */
1973:       1, 0, 4, 7,  /* left */
1974:     };

1976:     faceSize = faceSizeHex;
1977:     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
1978:     PetscSortInt(faceSizeHex, sortedIndices);
1979:     for (iFace = 0; iFace < 6; ++iFace) {
1980:       const PetscInt ii = iFace*faceSizeHex;
1981:       PetscInt       fVertex, cVertex;

1983:       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
1984:           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
1985:           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
1986:           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
1987:         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
1988:           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
1989:             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
1990:               faceVertices[fVertex] = origVertices[cVertex];
1991:               break;
1992:             }
1993:           }
1994:         }
1995:         found = PETSC_TRUE;
1996:         break;
1997:       }
1998:     }
1999:     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2000:     if (posOriented) *posOriented = PETSC_TRUE;
2001:     return(0);
2002:   } else if (cellDim == 3 && numCorners == 10) {
2003:     /* Quadratic tet */
2004:     /* Faces are determined by the first 3 vertices (corners of faces) */
2005:     const PetscInt faceSizeTet = 6;
2006:     PetscInt       sortedIndices[6], i, iFace;
2007:     PetscBool      found                     = PETSC_FALSE;
2008:     PetscInt       faceVerticesTetSorted[24] = {
2009:       0, 1, 2,  6, 7, 8, /* bottom */
2010:       0, 3, 4,  6, 7, 9,  /* front */
2011:       1, 4, 5,  7, 8, 9,  /* right */
2012:       2, 3, 5,  6, 8, 9,  /* left */
2013:     };
2014:     PetscInt       faceVerticesTet[24] = {
2015:       0, 1, 2,  6, 7, 8, /* bottom */
2016:       0, 4, 3,  6, 7, 9,  /* front */
2017:       1, 5, 4,  7, 8, 9,  /* right */
2018:       2, 3, 5,  8, 6, 9,  /* left */
2019:     };

2021:     faceSize = faceSizeTet;
2022:     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
2023:     PetscSortInt(faceSizeTet, sortedIndices);
2024:     for (iFace=0; iFace < 4; ++iFace) {
2025:       const PetscInt ii = iFace*faceSizeTet;
2026:       PetscInt       fVertex, cVertex;

2028:       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
2029:           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
2030:           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
2031:           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
2032:         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
2033:           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
2034:             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
2035:               faceVertices[fVertex] = origVertices[cVertex];
2036:               break;
2037:             }
2038:           }
2039:         }
2040:         found = PETSC_TRUE;
2041:         break;
2042:       }
2043:     }
2044:     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
2045:     if (posOriented) *posOriented = PETSC_TRUE;
2046:     return(0);
2047:   } else if (cellDim == 3 && numCorners == 27) {
2048:     /* Quadratic hexes (I hate this)
2049:        A hex is two oriented quads with the normal of the first
2050:        pointing up at the second.

2052:          7---6
2053:         /|  /|
2054:        4---5 |
2055:        | 3-|-2
2056:        |/  |/
2057:        0---1

2059:        Faces are determined by the first 4 vertices (corners of faces) */
2060:     const PetscInt faceSizeQuadHex = 9;
2061:     PetscInt       sortedIndices[9], i, iFace;
2062:     PetscBool      found                         = PETSC_FALSE;
2063:     PetscInt       faceVerticesQuadHexSorted[54] = {
2064:       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
2065:       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
2066:       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
2067:       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
2068:       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
2069:       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
2070:     };
2071:     PetscInt       faceVerticesQuadHex[54] = {
2072:       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
2073:       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
2074:       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
2075:       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
2076:       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
2077:       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
2078:     };

2080:     faceSize = faceSizeQuadHex;
2081:     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
2082:     PetscSortInt(faceSizeQuadHex, sortedIndices);
2083:     for (iFace = 0; iFace < 6; ++iFace) {
2084:       const PetscInt ii = iFace*faceSizeQuadHex;
2085:       PetscInt       fVertex, cVertex;

2087:       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
2088:           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
2089:           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
2090:           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
2091:         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
2092:           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
2093:             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
2094:               faceVertices[fVertex] = origVertices[cVertex];
2095:               break;
2096:             }
2097:           }
2098:         }
2099:         found = PETSC_TRUE;
2100:         break;
2101:       }
2102:     }
2103:     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2104:     if (posOriented) *posOriented = PETSC_TRUE;
2105:     return(0);
2106:   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
2107:   if (!posOrient) {
2108:     if (debug) {PetscPrintf(comm, "  Reversing initial face orientation\n");}
2109:     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
2110:   } else {
2111:     if (debug) {PetscPrintf(comm, "  Keeping initial face orientation\n");}
2112:     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
2113:   }
2114:   if (posOriented) *posOriented = posOrient;
2115:   return(0);
2116: }

2120: /*
2121:     Given a cell and a face, as a set of vertices,
2122:       return the oriented face, as a set of vertices, in faceVertices
2123:     The orientation is such that the face normal points out of the cell
2124: */
2125: PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2126: {
2127:   const PetscInt *cone = NULL;
2128:   PetscInt        coneSize, v, f, v2;
2129:   PetscInt        oppositeVertex = -1;
2130:   PetscErrorCode  ierr;

2133:   DMPlexGetConeSize(dm, cell, &coneSize);
2134:   DMPlexGetCone(dm, cell, &cone);
2135:   for (v = 0, v2 = 0; v < coneSize; ++v) {
2136:     PetscBool found = PETSC_FALSE;

2138:     for (f = 0; f < faceSize; ++f) {
2139:       if (face[f] == cone[v]) {
2140:         found = PETSC_TRUE; break;
2141:       }
2142:     }
2143:     if (found) {
2144:       indices[v2]      = v;
2145:       origVertices[v2] = cone[v];
2146:       ++v2;
2147:     } else {
2148:       oppositeVertex = v;
2149:     }
2150:   }
2151:   DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);
2152:   return(0);
2153: }

2157: /*
2158:   DMPlexInsertFace_Internal - Puts a face into the mesh

2160:   Not collective

2162:   Input Parameters:
2163:   + dm              - The DMPlex
2164:   . numFaceVertex   - The number of vertices in the face
2165:   . faceVertices    - The vertices in the face for dm
2166:   . subfaceVertices - The vertices in the face for subdm
2167:   . numCorners      - The number of vertices in the cell
2168:   . cell            - A cell in dm containing the face
2169:   . subcell         - A cell in subdm containing the face
2170:   . firstFace       - First face in the mesh
2171:   - newFacePoint    - Next face in the mesh

2173:   Output Parameters:
2174:   . newFacePoint - Contains next face point number on input, updated on output

2176:   Level: developer
2177: */
2178: 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)
2179: {
2180:   MPI_Comm        comm;
2181:   DM_Plex        *submesh = (DM_Plex*) subdm->data;
2182:   const PetscInt *faces;
2183:   PetscInt        numFaces, coneSize;
2184:   PetscErrorCode  ierr;

2187:   PetscObjectGetComm((PetscObject)dm,&comm);
2188:   DMPlexGetConeSize(subdm, subcell, &coneSize);
2189:   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
2190: #if 0
2191:   /* Cannot use this because support() has not been constructed yet */
2192:   DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);
2193: #else
2194:   {
2195:     PetscInt f;

2197:     numFaces = 0;
2198:     DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);
2199:     for (f = firstFace; f < *newFacePoint; ++f) {
2200:       PetscInt dof, off, d;

2202:       PetscSectionGetDof(submesh->coneSection, f, &dof);
2203:       PetscSectionGetOffset(submesh->coneSection, f, &off);
2204:       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
2205:       for (d = 0; d < dof; ++d) {
2206:         const PetscInt p = submesh->cones[off+d];
2207:         PetscInt       v;

2209:         for (v = 0; v < numFaceVertices; ++v) {
2210:           if (subfaceVertices[v] == p) break;
2211:         }
2212:         if (v == numFaceVertices) break;
2213:       }
2214:       if (d == dof) {
2215:         numFaces               = 1;
2216:         ((PetscInt*) faces)[0] = f;
2217:       }
2218:     }
2219:   }
2220: #endif
2221:   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
2222:   else if (numFaces == 1) {
2223:     /* Add the other cell neighbor for this face */
2224:     DMPlexSetCone(subdm, subcell, faces);
2225:   } else {
2226:     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
2227:     PetscBool posOriented;

2229:     DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);
2230:     origVertices        = &orientedVertices[numFaceVertices];
2231:     indices             = &orientedVertices[numFaceVertices*2];
2232:     orientedSubVertices = &orientedVertices[numFaceVertices*3];
2233:     DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);
2234:     /* TODO: I know that routine should return a permutation, not the indices */
2235:     for (v = 0; v < numFaceVertices; ++v) {
2236:       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
2237:       for (ov = 0; ov < numFaceVertices; ++ov) {
2238:         if (orientedVertices[ov] == vertex) {
2239:           orientedSubVertices[ov] = subvertex;
2240:           break;
2241:         }
2242:       }
2243:       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
2244:     }
2245:     DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);
2246:     DMPlexSetCone(subdm, subcell, newFacePoint);
2247:     DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);
2248:     ++(*newFacePoint);
2249:   }
2250: #if 0
2251:   DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);
2252: #else
2253:   DMRestoreWorkArray(subdm, 1, PETSC_INT, (void **) &faces);
2254: #endif
2255:   return(0);
2256: }

2260: static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm)
2261: {
2262:   MPI_Comm        comm;
2263:   DMLabel         subpointMap;
2264:   IS              subvertexIS,  subcellIS;
2265:   const PetscInt *subVertices, *subCells;
2266:   PetscInt        numSubVertices, firstSubVertex, numSubCells;
2267:   PetscInt       *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0;
2268:   PetscInt        vStart, vEnd, c, f;
2269:   PetscErrorCode  ierr;

2272:   PetscObjectGetComm((PetscObject)dm,&comm);
2273:   /* Create subpointMap which marks the submesh */
2274:   DMLabelCreate("subpoint_map", &subpointMap);
2275:   DMPlexSetSubpointMap(subdm, subpointMap);
2276:   DMLabelDestroy(&subpointMap);
2277:   if (vertexLabel) {DMPlexMarkSubmesh_Uninterpolated(dm, vertexLabel, value, subpointMap, &numSubFaces, &nFV, subdm);}
2278:   /* Setup chart */
2279:   DMLabelGetStratumSize(subpointMap, 0, &numSubVertices);
2280:   DMLabelGetStratumSize(subpointMap, 2, &numSubCells);
2281:   DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVertices);
2282:   DMPlexSetVTKCellHeight(subdm, 1);
2283:   /* Set cone sizes */
2284:   firstSubVertex = numSubCells;
2285:   firstSubFace   = numSubCells+numSubVertices;
2286:   newFacePoint   = firstSubFace;
2287:   DMLabelGetStratumIS(subpointMap, 0, &subvertexIS);
2288:   if (subvertexIS) {ISGetIndices(subvertexIS, &subVertices);}
2289:   DMLabelGetStratumIS(subpointMap, 2, &subcellIS);
2290:   if (subcellIS) {ISGetIndices(subcellIS, &subCells);}
2291:   for (c = 0; c < numSubCells; ++c) {
2292:     DMPlexSetConeSize(subdm, c, 1);
2293:   }
2294:   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
2295:     DMPlexSetConeSize(subdm, f, nFV);
2296:   }
2297:   DMSetUp(subdm);
2298:   /* Create face cones */
2299:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
2300:   DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2301:   DMGetWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
2302:   for (c = 0; c < numSubCells; ++c) {
2303:     const PetscInt cell    = subCells[c];
2304:     const PetscInt subcell = c;
2305:     PetscInt      *closure = NULL;
2306:     PetscInt       closureSize, cl, numCorners = 0, faceSize = 0;

2308:     DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
2309:     for (cl = 0; cl < closureSize*2; cl += 2) {
2310:       const PetscInt point = closure[cl];
2311:       PetscInt       subVertex;

2313:       if ((point >= vStart) && (point < vEnd)) {
2314:         ++numCorners;
2315:         PetscFindInt(point, numSubVertices, subVertices, &subVertex);
2316:         if (subVertex >= 0) {
2317:           closure[faceSize] = point;
2318:           subface[faceSize] = firstSubVertex+subVertex;
2319:           ++faceSize;
2320:         }
2321:       }
2322:     }
2323:     if (faceSize > nFV) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
2324:     if (faceSize == nFV) {
2325:       DMPlexInsertFace_Internal(dm, subdm, faceSize, closure, subface, numCorners, cell, subcell, firstSubFace, &newFacePoint);
2326:     }
2327:     DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);
2328:   }
2329:   DMRestoreWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
2330:   DMPlexSymmetrize(subdm);
2331:   DMPlexStratify(subdm);
2332:   /* Build coordinates */
2333:   {
2334:     PetscSection coordSection, subCoordSection;
2335:     Vec          coordinates, subCoordinates;
2336:     PetscScalar *coords, *subCoords;
2337:     PetscInt     numComp, coordSize, v;

2339:     DMGetCoordinateSection(dm, &coordSection);
2340:     DMGetCoordinatesLocal(dm, &coordinates);
2341:     DMGetCoordinateSection(subdm, &subCoordSection);
2342:     PetscSectionSetNumFields(subCoordSection, 1);
2343:     PetscSectionGetFieldComponents(coordSection, 0, &numComp);
2344:     PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
2345:     PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);
2346:     for (v = 0; v < numSubVertices; ++v) {
2347:       const PetscInt vertex    = subVertices[v];
2348:       const PetscInt subvertex = firstSubVertex+v;
2349:       PetscInt       dof;

2351:       PetscSectionGetDof(coordSection, vertex, &dof);
2352:       PetscSectionSetDof(subCoordSection, subvertex, dof);
2353:       PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
2354:     }
2355:     PetscSectionSetUp(subCoordSection);
2356:     PetscSectionGetStorageSize(subCoordSection, &coordSize);
2357:     VecCreate(comm, &subCoordinates);
2358:     VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
2359:     VecSetType(subCoordinates,VECSTANDARD);
2360:     if (coordSize) {
2361:       VecGetArray(coordinates,    &coords);
2362:       VecGetArray(subCoordinates, &subCoords);
2363:       for (v = 0; v < numSubVertices; ++v) {
2364:         const PetscInt vertex    = subVertices[v];
2365:         const PetscInt subvertex = firstSubVertex+v;
2366:         PetscInt       dof, off, sdof, soff, d;

2368:         PetscSectionGetDof(coordSection, vertex, &dof);
2369:         PetscSectionGetOffset(coordSection, vertex, &off);
2370:         PetscSectionGetDof(subCoordSection, subvertex, &sdof);
2371:         PetscSectionGetOffset(subCoordSection, subvertex, &soff);
2372:         if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
2373:         for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
2374:       }
2375:       VecRestoreArray(coordinates,    &coords);
2376:       VecRestoreArray(subCoordinates, &subCoords);
2377:     }
2378:     DMSetCoordinatesLocal(subdm, subCoordinates);
2379:     VecDestroy(&subCoordinates);
2380:   }
2381:   /* Cleanup */
2382:   if (subvertexIS) {ISRestoreIndices(subvertexIS, &subVertices);}
2383:   ISDestroy(&subvertexIS);
2384:   if (subcellIS) {ISRestoreIndices(subcellIS, &subCells);}
2385:   ISDestroy(&subcellIS);
2386:   return(0);
2387: }

2391: static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm)
2392: {
2393:   MPI_Comm         comm;
2394:   DMLabel          subpointMap;
2395:   IS              *subpointIS;
2396:   const PetscInt **subpoints;
2397:   PetscInt        *numSubPoints, *firstSubPoint, *coneNew, *coneONew;
2398:   PetscInt         totSubPoints = 0, maxConeSize, dim, p, d, v;
2399:   PetscErrorCode   ierr;

2402:   PetscObjectGetComm((PetscObject)dm,&comm);
2403:   /* Create subpointMap which marks the submesh */
2404:   DMLabelCreate("subpoint_map", &subpointMap);
2405:   DMPlexSetSubpointMap(subdm, subpointMap);
2406:   DMLabelDestroy(&subpointMap);
2407:   if (vertexLabel) {DMPlexMarkSubmesh_Interpolated(dm, vertexLabel, value, subpointMap, subdm);}
2408:   /* Setup chart */
2409:   DMPlexGetDimension(dm, &dim);
2410:   PetscMalloc4(dim+1,&numSubPoints,dim+1,&firstSubPoint,dim+1,&subpointIS,dim+1,&subpoints);
2411:   for (d = 0; d <= dim; ++d) {
2412:     DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d]);
2413:     totSubPoints += numSubPoints[d];
2414:   }
2415:   DMPlexSetChart(subdm, 0, totSubPoints);
2416:   DMPlexSetVTKCellHeight(subdm, 1);
2417:   /* Set cone sizes */
2418:   firstSubPoint[dim] = 0;
2419:   firstSubPoint[0]   = firstSubPoint[dim] + numSubPoints[dim];
2420:   if (dim > 1) {firstSubPoint[dim-1] = firstSubPoint[0]     + numSubPoints[0];}
2421:   if (dim > 2) {firstSubPoint[dim-2] = firstSubPoint[dim-1] + numSubPoints[dim-1];}
2422:   for (d = 0; d <= dim; ++d) {
2423:     DMLabelGetStratumIS(subpointMap, d, &subpointIS[d]);
2424:     if (subpointIS[d]) {ISGetIndices(subpointIS[d], &subpoints[d]);}
2425:   }
2426:   for (d = 0; d <= dim; ++d) {
2427:     for (p = 0; p < numSubPoints[d]; ++p) {
2428:       const PetscInt  point    = subpoints[d][p];
2429:       const PetscInt  subpoint = firstSubPoint[d] + p;
2430:       const PetscInt *cone;
2431:       PetscInt        coneSize, coneSizeNew, c, val;

2433:       DMPlexGetConeSize(dm, point, &coneSize);
2434:       DMPlexSetConeSize(subdm, subpoint, coneSize);
2435:       if (d == dim) {
2436:         DMPlexGetCone(dm, point, &cone);
2437:         for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
2438:           DMLabelGetValue(subpointMap, cone[c], &val);
2439:           if (val >= 0) coneSizeNew++;
2440:         }
2441:         DMPlexSetConeSize(subdm, subpoint, coneSizeNew);
2442:       }
2443:     }
2444:   }
2445:   DMSetUp(subdm);
2446:   /* Set cones */
2447:   DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2448:   PetscMalloc2(maxConeSize,&coneNew,maxConeSize,&coneONew);
2449:   for (d = 0; d <= dim; ++d) {
2450:     for (p = 0; p < numSubPoints[d]; ++p) {
2451:       const PetscInt  point    = subpoints[d][p];
2452:       const PetscInt  subpoint = firstSubPoint[d] + p;
2453:       const PetscInt *cone, *ornt;
2454:       PetscInt        coneSize, subconeSize, coneSizeNew, c, subc;

2456:       DMPlexGetConeSize(dm, point, &coneSize);
2457:       DMPlexGetConeSize(subdm, subpoint, &subconeSize);
2458:       DMPlexGetCone(dm, point, &cone);
2459:       DMPlexGetConeOrientation(dm, point, &ornt);
2460:       for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
2461:         PetscFindInt(cone[c], numSubPoints[d-1], subpoints[d-1], &subc);
2462:         if (subc >= 0) {
2463:           coneNew[coneSizeNew]  = firstSubPoint[d-1] + subc;
2464:           coneONew[coneSizeNew] = ornt[c];
2465:           ++coneSizeNew;
2466:         }
2467:       }
2468:       if (coneSizeNew != subconeSize) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of cone points located %d does not match subcone size %d", coneSizeNew, subconeSize);
2469:       DMPlexSetCone(subdm, subpoint, coneNew);
2470:       DMPlexSetConeOrientation(subdm, subpoint, coneONew);
2471:     }
2472:   }
2473:   PetscFree2(coneNew,coneONew);
2474:   DMPlexSymmetrize(subdm);
2475:   DMPlexStratify(subdm);
2476:   /* Build coordinates */
2477:   {
2478:     PetscSection coordSection, subCoordSection;
2479:     Vec          coordinates, subCoordinates;
2480:     PetscScalar *coords, *subCoords;
2481:     PetscInt     numComp, coordSize;

2483:     DMGetCoordinateSection(dm, &coordSection);
2484:     DMGetCoordinatesLocal(dm, &coordinates);
2485:     DMGetCoordinateSection(subdm, &subCoordSection);
2486:     PetscSectionSetNumFields(subCoordSection, 1);
2487:     PetscSectionGetFieldComponents(coordSection, 0, &numComp);
2488:     PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
2489:     PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0]+numSubPoints[0]);
2490:     for (v = 0; v < numSubPoints[0]; ++v) {
2491:       const PetscInt vertex    = subpoints[0][v];
2492:       const PetscInt subvertex = firstSubPoint[0]+v;
2493:       PetscInt       dof;

2495:       PetscSectionGetDof(coordSection, vertex, &dof);
2496:       PetscSectionSetDof(subCoordSection, subvertex, dof);
2497:       PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
2498:     }
2499:     PetscSectionSetUp(subCoordSection);
2500:     PetscSectionGetStorageSize(subCoordSection, &coordSize);
2501:     VecCreate(comm, &subCoordinates);
2502:     VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
2503:     VecSetType(subCoordinates,VECSTANDARD);
2504:     VecGetArray(coordinates,    &coords);
2505:     VecGetArray(subCoordinates, &subCoords);
2506:     for (v = 0; v < numSubPoints[0]; ++v) {
2507:       const PetscInt vertex    = subpoints[0][v];
2508:       const PetscInt subvertex = firstSubPoint[0]+v;
2509:       PetscInt dof, off, sdof, soff, d;

2511:       PetscSectionGetDof(coordSection, vertex, &dof);
2512:       PetscSectionGetOffset(coordSection, vertex, &off);
2513:       PetscSectionGetDof(subCoordSection, subvertex, &sdof);
2514:       PetscSectionGetOffset(subCoordSection, subvertex, &soff);
2515:       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
2516:       for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
2517:     }
2518:     VecRestoreArray(coordinates,    &coords);
2519:     VecRestoreArray(subCoordinates, &subCoords);
2520:     DMSetCoordinatesLocal(subdm, subCoordinates);
2521:     VecDestroy(&subCoordinates);
2522:   }
2523:   /* Cleanup */
2524:   for (d = 0; d <= dim; ++d) {
2525:     if (subpointIS[d]) {ISRestoreIndices(subpointIS[d], &subpoints[d]);}
2526:     ISDestroy(&subpointIS[d]);
2527:   }
2528:   PetscFree4(numSubPoints,firstSubPoint,subpointIS,subpoints);
2529:   return(0);
2530: }

2534: /*@
2535:   DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label

2537:   Input Parameters:
2538: + dm           - The original mesh
2539: . vertexLabel  - The DMLabel marking vertices contained in the surface
2540: - value        - The label value to use

2542:   Output Parameter:
2543: . subdm - The surface mesh

2545:   Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().

2547:   Level: developer

2549: .seealso: DMPlexGetSubpointMap(), DMPlexGetLabel(), DMLabelSetValue()
2550: @*/
2551: PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, DM *subdm)
2552: {
2553:   PetscInt       dim, depth;

2559:   DMPlexGetDimension(dm, &dim);
2560:   DMPlexGetDepth(dm, &depth);
2561:   DMCreate(PetscObjectComm((PetscObject)dm), subdm);
2562:   DMSetType(*subdm, DMPLEX);
2563:   DMPlexSetDimension(*subdm, dim-1);
2564:   if (depth == dim) {
2565:     DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, *subdm);
2566:   } else {
2567:     DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm);
2568:   }
2569:   return(0);
2570: }

2574: PETSC_STATIC_INLINE PetscInt DMPlexFilterPoint_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[])
2575: {
2576:   PetscInt       subPoint;

2579:   PetscFindInt(point, numSubPoints, subPoints, &subPoint); if (ierr < 0) return ierr;
2580:   return subPoint < 0 ? subPoint : firstSubPoint+subPoint;
2581: }

2585: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm)
2586: {
2587:   MPI_Comm        comm;
2588:   DMLabel         subpointMap;
2589:   IS              subvertexIS;
2590:   const PetscInt *subVertices;
2591:   PetscInt        numSubVertices, firstSubVertex, numSubCells, *subCells = NULL;
2592:   PetscInt       *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV;
2593:   PetscInt        cMax, c, f;
2594:   PetscErrorCode  ierr;

2597:   PetscObjectGetComm((PetscObject)dm, &comm);
2598:   /* Create subpointMap which marks the submesh */
2599:   DMLabelCreate("subpoint_map", &subpointMap);
2600:   DMPlexSetSubpointMap(subdm, subpointMap);
2601:   DMLabelDestroy(&subpointMap);
2602:   DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm);
2603:   /* Setup chart */
2604:   DMLabelGetStratumSize(subpointMap, 0, &numSubVertices);
2605:   DMLabelGetStratumSize(subpointMap, 2, &numSubCells);
2606:   DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVertices);
2607:   DMPlexSetVTKCellHeight(subdm, 1);
2608:   /* Set cone sizes */
2609:   firstSubVertex = numSubCells;
2610:   firstSubFace   = numSubCells+numSubVertices;
2611:   newFacePoint   = firstSubFace;
2612:   DMLabelGetStratumIS(subpointMap, 0, &subvertexIS);
2613:   if (subvertexIS) {ISGetIndices(subvertexIS, &subVertices);}
2614:   for (c = 0; c < numSubCells; ++c) {
2615:     DMPlexSetConeSize(subdm, c, 1);
2616:   }
2617:   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
2618:     DMPlexSetConeSize(subdm, f, nFV);
2619:   }
2620:   DMSetUp(subdm);
2621:   /* Create face cones */
2622:   DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2623:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
2624:   DMGetWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
2625:   for (c = 0; c < numSubCells; ++c) {
2626:     const PetscInt  cell    = subCells[c];
2627:     const PetscInt  subcell = c;
2628:     const PetscInt *cone, *cells;
2629:     PetscInt        numCells, subVertex, p, v;

2631:     if (cell < cMax) continue;
2632:     DMPlexGetCone(dm, cell, &cone);
2633:     for (v = 0; v < nFV; ++v) {
2634:       PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex);
2635:       subface[v] = firstSubVertex+subVertex;
2636:     }
2637:     DMPlexSetCone(subdm, newFacePoint, subface);
2638:     DMPlexSetCone(subdm, subcell, &newFacePoint);
2639:     DMPlexGetJoin(dm, nFV, cone, &numCells, &cells);
2640:     /* Not true in parallel
2641:     if (numCells != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
2642:     for (p = 0; p < numCells; ++p) {
2643:       PetscInt negsubcell;

2645:       if (cells[p] >= cMax) continue;
2646:       /* I know this is a crap search */
2647:       for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) {
2648:         if (subCells[negsubcell] == cells[p]) break;
2649:       }
2650:       if (negsubcell == numSubCells) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %d", cell);
2651:       DMPlexSetCone(subdm, negsubcell, &newFacePoint);
2652:     }
2653:     DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells);
2654:     ++newFacePoint;
2655:   }
2656:   DMRestoreWorkArray(subdm, maxConeSize, PETSC_INT, (void**) &subface);
2657:   DMPlexSymmetrize(subdm);
2658:   DMPlexStratify(subdm);
2659:   /* Build coordinates */
2660:   {
2661:     PetscSection coordSection, subCoordSection;
2662:     Vec          coordinates, subCoordinates;
2663:     PetscScalar *coords, *subCoords;
2664:     PetscInt     numComp, coordSize, v;

2666:     DMGetCoordinateSection(dm, &coordSection);
2667:     DMGetCoordinatesLocal(dm, &coordinates);
2668:     DMGetCoordinateSection(subdm, &subCoordSection);
2669:     PetscSectionSetNumFields(subCoordSection, 1);
2670:     PetscSectionGetFieldComponents(coordSection, 0, &numComp);
2671:     PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
2672:     PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);
2673:     for (v = 0; v < numSubVertices; ++v) {
2674:       const PetscInt vertex    = subVertices[v];
2675:       const PetscInt subvertex = firstSubVertex+v;
2676:       PetscInt       dof;

2678:       PetscSectionGetDof(coordSection, vertex, &dof);
2679:       PetscSectionSetDof(subCoordSection, subvertex, dof);
2680:       PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
2681:     }
2682:     PetscSectionSetUp(subCoordSection);
2683:     PetscSectionGetStorageSize(subCoordSection, &coordSize);
2684:     VecCreate(comm, &subCoordinates);
2685:     VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
2686:     VecSetType(subCoordinates,VECSTANDARD);
2687:     VecGetArray(coordinates,    &coords);
2688:     VecGetArray(subCoordinates, &subCoords);
2689:     for (v = 0; v < numSubVertices; ++v) {
2690:       const PetscInt vertex    = subVertices[v];
2691:       const PetscInt subvertex = firstSubVertex+v;
2692:       PetscInt       dof, off, sdof, soff, d;

2694:       PetscSectionGetDof(coordSection, vertex, &dof);
2695:       PetscSectionGetOffset(coordSection, vertex, &off);
2696:       PetscSectionGetDof(subCoordSection, subvertex, &sdof);
2697:       PetscSectionGetOffset(subCoordSection, subvertex, &soff);
2698:       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
2699:       for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
2700:     }
2701:     VecRestoreArray(coordinates,    &coords);
2702:     VecRestoreArray(subCoordinates, &subCoords);
2703:     DMSetCoordinatesLocal(subdm, subCoordinates);
2704:     VecDestroy(&subCoordinates);
2705:   }
2706:   /* Build SF */
2707:   CHKMEMQ;
2708:   {
2709:     PetscSF            sfPoint, sfPointSub;
2710:     const PetscSFNode *remotePoints;
2711:     PetscSFNode       *sremotePoints, *newLocalPoints, *newOwners;
2712:     const PetscInt    *localPoints;
2713:     PetscInt          *slocalPoints;
2714:     PetscInt           numRoots, numLeaves, numSubRoots = numSubCells+numSubFaces+numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd;
2715:     PetscMPIInt        rank;

2717:     MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
2718:     DMGetPointSF(dm, &sfPoint);
2719:     DMGetPointSF(subdm, &sfPointSub);
2720:     DMPlexGetChart(dm, &pStart, &pEnd);
2721:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
2722:     PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
2723:     if (numRoots >= 0) {
2724:       /* Only vertices should be shared */
2725:       PetscMalloc2(pEnd-pStart,&newLocalPoints,numRoots,&newOwners);
2726:       for (p = 0; p < pEnd-pStart; ++p) {
2727:         newLocalPoints[p].rank  = -2;
2728:         newLocalPoints[p].index = -2;
2729:       }
2730:       /* Set subleaves */
2731:       for (l = 0; l < numLeaves; ++l) {
2732:         const PetscInt point    = localPoints[l];
2733:         const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);

2735:         if ((point < vStart) && (point >= vEnd)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %d", point);
2736:         if (subPoint < 0) continue;
2737:         newLocalPoints[point-pStart].rank  = rank;
2738:         newLocalPoints[point-pStart].index = subPoint;
2739:         ++numSubLeaves;
2740:       }
2741:       /* Must put in owned subpoints */
2742:       for (p = pStart; p < pEnd; ++p) {
2743:         const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices);

2745:         if (subPoint < 0) {
2746:           newOwners[p-pStart].rank  = -3;
2747:           newOwners[p-pStart].index = -3;
2748:         } else {
2749:           newOwners[p-pStart].rank  = rank;
2750:           newOwners[p-pStart].index = subPoint;
2751:         }
2752:       }
2753:       PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
2754:       PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
2755:       PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
2756:       PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
2757:       PetscMalloc1(numSubLeaves,    &slocalPoints);
2758:       PetscMalloc1(numSubLeaves, &sremotePoints);
2759:       for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) {
2760:         const PetscInt point    = localPoints[l];
2761:         const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);

2763:         if (subPoint < 0) continue;
2764:         if (newLocalPoints[point].rank == rank) {++ll; continue;}
2765:         slocalPoints[sl]        = subPoint;
2766:         sremotePoints[sl].rank  = newLocalPoints[point].rank;
2767:         sremotePoints[sl].index = newLocalPoints[point].index;
2768:         if (sremotePoints[sl].rank  < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %d", point);
2769:         if (sremotePoints[sl].index < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %d", point);
2770:         ++sl;
2771:       }
2772:       PetscFree2(newLocalPoints,newOwners);
2773:       if (sl + ll != numSubLeaves) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %d + %d != %d", sl, ll, numSubLeaves);
2774:       PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER);
2775:     }
2776:   }
2777:   CHKMEMQ;
2778:   /* Cleanup */
2779:   if (subvertexIS) {ISRestoreIndices(subvertexIS, &subVertices);}
2780:   ISDestroy(&subvertexIS);
2781:   PetscFree(subCells);
2782:   return(0);
2783: }

2787: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char label[], PetscInt value, DM subdm)
2788: {
2789:   MPI_Comm         comm;
2790:   DMLabel          subpointMap;
2791:   IS              *subpointIS;
2792:   const PetscInt **subpoints;
2793:   PetscInt        *numSubPoints, *firstSubPoint, *coneNew, *orntNew;
2794:   PetscInt         totSubPoints = 0, maxConeSize, dim, p, d, v;
2795:   PetscErrorCode   ierr;

2798:   PetscObjectGetComm((PetscObject)dm,&comm);
2799:   /* Create subpointMap which marks the submesh */
2800:   DMLabelCreate("subpoint_map", &subpointMap);
2801:   DMPlexSetSubpointMap(subdm, subpointMap);
2802:   DMLabelDestroy(&subpointMap);
2803:   DMPlexMarkCohesiveSubmesh_Interpolated(dm, label, value, subpointMap, subdm);
2804:   /* Setup chart */
2805:   DMPlexGetDimension(dm, &dim);
2806:   PetscMalloc4(dim+1,&numSubPoints,dim+1,&firstSubPoint,dim+1,&subpointIS,dim+1,&subpoints);
2807:   for (d = 0; d <= dim; ++d) {
2808:     DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d]);
2809:     totSubPoints += numSubPoints[d];
2810:   }
2811:   DMPlexSetChart(subdm, 0, totSubPoints);
2812:   DMPlexSetVTKCellHeight(subdm, 1);
2813:   /* Set cone sizes */
2814:   firstSubPoint[dim] = 0;
2815:   firstSubPoint[0]   = firstSubPoint[dim] + numSubPoints[dim];
2816:   if (dim > 1) {firstSubPoint[dim-1] = firstSubPoint[0]     + numSubPoints[0];}
2817:   if (dim > 2) {firstSubPoint[dim-2] = firstSubPoint[dim-1] + numSubPoints[dim-1];}
2818:   for (d = 0; d <= dim; ++d) {
2819:     DMLabelGetStratumIS(subpointMap, d, &subpointIS[d]);
2820:     if (subpointIS[d]) {ISGetIndices(subpointIS[d], &subpoints[d]);}
2821:   }
2822:   for (d = 0; d <= dim; ++d) {
2823:     for (p = 0; p < numSubPoints[d]; ++p) {
2824:       const PetscInt  point    = subpoints[d][p];
2825:       const PetscInt  subpoint = firstSubPoint[d] + p;
2826:       const PetscInt *cone;
2827:       PetscInt        coneSize, coneSizeNew, c, val;

2829:       DMPlexGetConeSize(dm, point, &coneSize);
2830:       DMPlexSetConeSize(subdm, subpoint, coneSize);
2831:       if (d == dim) {
2832:         DMPlexGetCone(dm, point, &cone);
2833:         for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
2834:           DMLabelGetValue(subpointMap, cone[c], &val);
2835:           if (val >= 0) coneSizeNew++;
2836:         }
2837:         DMPlexSetConeSize(subdm, subpoint, coneSizeNew);
2838:       }
2839:     }
2840:   }
2841:   DMSetUp(subdm);
2842:   /* Set cones */
2843:   DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2844:   PetscMalloc2(maxConeSize,&coneNew,maxConeSize,&orntNew);
2845:   for (d = 0; d <= dim; ++d) {
2846:     for (p = 0; p < numSubPoints[d]; ++p) {
2847:       const PetscInt  point    = subpoints[d][p];
2848:       const PetscInt  subpoint = firstSubPoint[d] + p;
2849:       const PetscInt *cone, *ornt;
2850:       PetscInt        coneSize, subconeSize, coneSizeNew, c, subc;

2852:       DMPlexGetConeSize(dm, point, &coneSize);
2853:       DMPlexGetConeSize(subdm, subpoint, &subconeSize);
2854:       DMPlexGetCone(dm, point, &cone);
2855:       DMPlexGetConeOrientation(dm, point, &ornt);
2856:       for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
2857:         PetscFindInt(cone[c], numSubPoints[d-1], subpoints[d-1], &subc);
2858:         if (subc >= 0) {
2859:           coneNew[coneSizeNew]   = firstSubPoint[d-1] + subc;
2860:           orntNew[coneSizeNew++] = ornt[c];
2861:         }
2862:       }
2863:       if (coneSizeNew != subconeSize) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of cone points located %d does not match subcone size %d", coneSizeNew, subconeSize);
2864:       DMPlexSetCone(subdm, subpoint, coneNew);
2865:       DMPlexSetConeOrientation(subdm, subpoint, orntNew);
2866:     }
2867:   }
2868:   PetscFree2(coneNew,orntNew);
2869:   DMPlexSymmetrize(subdm);
2870:   DMPlexStratify(subdm);
2871:   /* Build coordinates */
2872:   {
2873:     PetscSection coordSection, subCoordSection;
2874:     Vec          coordinates, subCoordinates;
2875:     PetscScalar *coords, *subCoords;
2876:     PetscInt     numComp, coordSize;

2878:     DMGetCoordinateSection(dm, &coordSection);
2879:     DMGetCoordinatesLocal(dm, &coordinates);
2880:     DMGetCoordinateSection(subdm, &subCoordSection);
2881:     PetscSectionSetNumFields(subCoordSection, 1);
2882:     PetscSectionGetFieldComponents(coordSection, 0, &numComp);
2883:     PetscSectionSetFieldComponents(subCoordSection, 0, numComp);
2884:     PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0]+numSubPoints[0]);
2885:     for (v = 0; v < numSubPoints[0]; ++v) {
2886:       const PetscInt vertex    = subpoints[0][v];
2887:       const PetscInt subvertex = firstSubPoint[0]+v;
2888:       PetscInt       dof;

2890:       PetscSectionGetDof(coordSection, vertex, &dof);
2891:       PetscSectionSetDof(subCoordSection, subvertex, dof);
2892:       PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof);
2893:     }
2894:     PetscSectionSetUp(subCoordSection);
2895:     PetscSectionGetStorageSize(subCoordSection, &coordSize);
2896:     VecCreate(comm, &subCoordinates);
2897:     VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);
2898:     VecSetType(subCoordinates,VECSTANDARD);
2899:     VecGetArray(coordinates,    &coords);
2900:     VecGetArray(subCoordinates, &subCoords);
2901:     for (v = 0; v < numSubPoints[0]; ++v) {
2902:       const PetscInt vertex    = subpoints[0][v];
2903:       const PetscInt subvertex = firstSubPoint[0]+v;
2904:       PetscInt dof, off, sdof, soff, d;

2906:       PetscSectionGetDof(coordSection, vertex, &dof);
2907:       PetscSectionGetOffset(coordSection, vertex, &off);
2908:       PetscSectionGetDof(subCoordSection, subvertex, &sdof);
2909:       PetscSectionGetOffset(subCoordSection, subvertex, &soff);
2910:       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
2911:       for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
2912:     }
2913:     VecRestoreArray(coordinates,    &coords);
2914:     VecRestoreArray(subCoordinates, &subCoords);
2915:     DMSetCoordinatesLocal(subdm, subCoordinates);
2916:     VecDestroy(&subCoordinates);
2917:   }
2918:   /* Build SF: We need this complexity because subpoints might not be selected on the owning process */
2919:   {
2920:     PetscSF            sfPoint, sfPointSub;
2921:     IS                 subpIS;
2922:     const PetscSFNode *remotePoints;
2923:     PetscSFNode       *sremotePoints, *newLocalPoints, *newOwners;
2924:     const PetscInt    *localPoints, *subpoints;
2925:     PetscInt          *slocalPoints;
2926:     PetscInt           numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl, ll, pStart, pEnd, p;
2927:     PetscMPIInt        rank;

2929:     MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
2930:     DMGetPointSF(dm, &sfPoint);
2931:     DMGetPointSF(subdm, &sfPointSub);
2932:     DMPlexGetChart(dm, &pStart, &pEnd);
2933:     DMPlexGetChart(subdm, NULL, &numSubroots);
2934:     DMPlexCreateSubpointIS(subdm, &subpIS);
2935:     if (subpIS) {
2936:       ISGetIndices(subpIS, &subpoints);
2937:       ISGetLocalSize(subpIS, &numSubpoints);
2938:     }
2939:     PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
2940:     if (numRoots >= 0) {
2941:       PetscMalloc2(pEnd-pStart,&newLocalPoints,numRoots,&newOwners);
2942:       for (p = 0; p < pEnd-pStart; ++p) {
2943:         newLocalPoints[p].rank  = -2;
2944:         newLocalPoints[p].index = -2;
2945:       }
2946:       /* Set subleaves */
2947:       for (l = 0; l < numLeaves; ++l) {
2948:         const PetscInt point    = localPoints[l];
2949:         const PetscInt subpoint = DMPlexFilterPoint_Internal(point, 0, numSubpoints, subpoints);

2951:         if (subpoint < 0) continue;
2952:         newLocalPoints[point-pStart].rank  = rank;
2953:         newLocalPoints[point-pStart].index = subpoint;
2954:         ++numSubleaves;
2955:       }
2956:       /* Must put in owned subpoints */
2957:       for (p = pStart; p < pEnd; ++p) {
2958:         const PetscInt subpoint = DMPlexFilterPoint_Internal(p, 0, numSubpoints, subpoints);

2960:         if (subpoint < 0) {
2961:           newOwners[p-pStart].rank  = -3;
2962:           newOwners[p-pStart].index = -3;
2963:         } else {
2964:           newOwners[p-pStart].rank  = rank;
2965:           newOwners[p-pStart].index = subpoint;
2966:         }
2967:       }
2968:       PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
2969:       PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC);
2970:       PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
2971:       PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints);
2972:       PetscMalloc(numSubleaves * sizeof(PetscInt),    &slocalPoints);
2973:       PetscMalloc(numSubleaves * sizeof(PetscSFNode), &sremotePoints);
2974:       for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) {
2975:         const PetscInt point    = localPoints[l];
2976:         const PetscInt subpoint = DMPlexFilterPoint_Internal(point, 0, numSubpoints, subpoints);

2978:         if (subpoint < 0) continue;
2979:         if (newLocalPoints[point].rank == rank) {++ll; continue;}
2980:         slocalPoints[sl]        = subpoint;
2981:         sremotePoints[sl].rank  = newLocalPoints[point].rank;
2982:         sremotePoints[sl].index = newLocalPoints[point].index;
2983:         if (sremotePoints[sl].rank  < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %d", point);
2984:         if (sremotePoints[sl].index < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %d", point);
2985:         ++sl;
2986:       }
2987:       if (sl + ll != numSubleaves) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %d + %d != %d", sl, ll, numSubleaves);
2988:       PetscFree2(newLocalPoints,newOwners);
2989:       PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER);
2990:     }
2991:     if (subpIS) {
2992:       ISRestoreIndices(subpIS, &subpoints);
2993:       ISDestroy(&subpIS);
2994:     }
2995:   }
2996:   /* Cleanup */
2997:   for (d = 0; d <= dim; ++d) {
2998:     if (subpointIS[d]) {ISRestoreIndices(subpointIS[d], &subpoints[d]);}
2999:     ISDestroy(&subpointIS[d]);
3000:   }
3001:   PetscFree4(numSubPoints,firstSubPoint,subpointIS,subpoints);
3002:   return(0);
3003: }

3007: /*
3008:   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.

3010:   Input Parameters:
3011: + dm          - The original mesh
3012: . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells
3013: . label       - A label name, or PETSC_NULL
3014: - value  - A label value

3016:   Output Parameter:
3017: . subdm - The surface mesh

3019:   Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().

3021:   Level: developer

3023: .seealso: DMPlexGetSubpointMap(), DMPlexCreateSubmesh()
3024: */
3025: PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm)
3026: {
3027:   PetscInt       dim, depth;

3033:   DMPlexGetDimension(dm, &dim);
3034:   DMPlexGetDepth(dm, &depth);
3035:   DMCreate(PetscObjectComm((PetscObject)dm), subdm);
3036:   DMSetType(*subdm, DMPLEX);
3037:   DMPlexSetDimension(*subdm, dim-1);
3038:   if (depth == dim) {
3039:     DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm);
3040:   } else {
3041:     DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm);
3042:   }
3043:   return(0);
3044: }

3048: /*@
3049:   DMPlexGetSubpointMap - Returns a DMLabel with point dimension as values

3051:   Input Parameter:
3052: . dm - The submesh DM

3054:   Output Parameter:
3055: . subpointMap - The DMLabel of all the points from the original mesh in this submesh, or NULL if this is not a submesh

3057:   Level: developer

3059: .seealso: DMPlexCreateSubmesh(), DMPlexCreateSubpointIS()
3060: @*/
3061: PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap)
3062: {
3063:   DM_Plex *mesh = (DM_Plex*) dm->data;

3068:   *subpointMap = mesh->subpointMap;
3069:   return(0);
3070: }

3074: /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
3075: PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap)
3076: {
3077:   DM_Plex       *mesh = (DM_Plex *) dm->data;
3078:   DMLabel        tmp;

3083:   tmp  = mesh->subpointMap;
3084:   mesh->subpointMap = subpointMap;
3085:   ++mesh->subpointMap->refct;
3086:   DMLabelDestroy(&tmp);
3087:   return(0);
3088: }

3092: /*@
3093:   DMPlexCreateSubpointIS - Creates an IS covering the entire subdm chart with the original points as data

3095:   Input Parameter:
3096: . dm - The submesh DM

3098:   Output Parameter:
3099: . subpointIS - The IS of all the points from the original mesh in this submesh, or NULL if this is not a submesh

3101:   Note: This is IS is guaranteed to be sorted by the construction of the submesh

3103:   Level: developer

3105: .seealso: DMPlexCreateSubmesh(), DMPlexGetSubpointMap()
3106: @*/
3107: PetscErrorCode DMPlexCreateSubpointIS(DM dm, IS *subpointIS)
3108: {
3109:   MPI_Comm        comm;
3110:   DMLabel         subpointMap;
3111:   IS              is;
3112:   const PetscInt *opoints;
3113:   PetscInt       *points, *depths;
3114:   PetscInt        depth, depStart, depEnd, d, pStart, pEnd, p, n, off;
3115:   PetscErrorCode  ierr;

3120:   PetscObjectGetComm((PetscObject)dm,&comm);
3121:   *subpointIS = NULL;
3122:   DMPlexGetSubpointMap(dm, &subpointMap);
3123:   DMPlexGetDepth(dm, &depth);
3124:   if (subpointMap && depth >= 0) {
3125:     DMPlexGetChart(dm, &pStart, &pEnd);
3126:     if (pStart) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %d", pStart);
3127:     DMGetWorkArray(dm, depth+1, PETSC_INT, &depths);
3128:     depths[0] = depth;
3129:     depths[1] = 0;
3130:     for(d = 2; d <= depth; ++d) {depths[d] = depth+1 - d;}
3131:     PetscMalloc1(pEnd, &points);
3132:     for(d = 0, off = 0; d <= depth; ++d) {
3133:       const PetscInt dep = depths[d];

3135:       DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd);
3136:       DMLabelGetStratumSize(subpointMap, dep, &n);
3137:       if (((d < 2) && (depth > 1)) || (d == 1)) { /* Only check vertices and cells for now since the map is broken for others */
3138:         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);
3139:       } else {
3140:         if (!n) {
3141:           if (d == 0) {
3142:             /* Missing cells */
3143:             for(p = 0; p < depEnd-depStart; ++p, ++off) points[off] = -1;
3144:           } else {
3145:             /* Missing faces */
3146:             for(p = 0; p < depEnd-depStart; ++p, ++off) points[off] = PETSC_MAX_INT;
3147:           }
3148:         }
3149:       }
3150:       if (n) {
3151:         DMLabelGetStratumIS(subpointMap, dep, &is);
3152:         ISGetIndices(is, &opoints);
3153:         for(p = 0; p < n; ++p, ++off) points[off] = opoints[p];
3154:         ISRestoreIndices(is, &opoints);
3155:         ISDestroy(&is);
3156:       }
3157:     }
3158:     DMRestoreWorkArray(dm, depth+1, PETSC_INT, &depths);
3159:     if (off != pEnd) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %d should be %d", off, pEnd);
3160:     ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS);
3161:   }
3162:   return(0);
3163: }