Actual source code: plexcreate.c

  1: #define PETSCDM_DLL
  2: #include <petsc/private/dmpleximpl.h>
  3: #include <petsc/private/hashseti.h>
  4: #include <petscsf.h>
  5: #include <petscdmplextransform.h>
  6: #include <petscdmlabelephemeral.h>
  7: #include <petsc/private/kernels/blockmatmult.h>
  8: #include <petsc/private/kernels/blockinvert.h>

 10: #ifdef PETSC_HAVE_UNISTD_H
 11:   #include <unistd.h>
 12: #endif
 13: #include <errno.h>

 15: PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_CreateFromOptions, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList;

 17: /* External function declarations here */
 18: static PetscErrorCode DMInitialize_Plex(DM dm);

 20: /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */
 21: PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout)
 22: {
 23:   const PetscReal     *maxCell, *Lstart, *L;
 24:   VecType              vecType;
 25:   MatType              matType;
 26:   PetscBool            dist, useCeed;
 27:   DMReorderDefaultFlag reorder;

 29:   PetscFunctionBegin;
 30:   PetscCall(DMGetVecType(dmin, &vecType));
 31:   PetscCall(DMSetVecType(dmout, vecType));
 32:   PetscCall(DMGetMatType(dmin, &matType));
 33:   PetscCall(DMSetMatType(dmout, matType));
 34:   if (copyPeriodicity) {
 35:     PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L));
 36:     PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L));
 37:   }
 38:   PetscCall(DMPlexDistributeGetDefault(dmin, &dist));
 39:   PetscCall(DMPlexDistributeSetDefault(dmout, dist));
 40:   PetscCall(DMPlexReorderGetDefault(dmin, &reorder));
 41:   PetscCall(DMPlexReorderSetDefault(dmout, reorder));
 42:   PetscCall(DMPlexGetUseCeed(dmin, &useCeed));
 43:   PetscCall(DMPlexSetUseCeed(dmout, useCeed));
 44:   ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation;
 45:   ((DM_Plex *)dmout->data)->printSetValues  = ((DM_Plex *)dmin->data)->printSetValues;
 46:   ((DM_Plex *)dmout->data)->printFEM        = ((DM_Plex *)dmin->data)->printFEM;
 47:   ((DM_Plex *)dmout->data)->printFVM        = ((DM_Plex *)dmin->data)->printFVM;
 48:   ((DM_Plex *)dmout->data)->printL2         = ((DM_Plex *)dmin->data)->printL2;
 49:   ((DM_Plex *)dmout->data)->printLocate     = ((DM_Plex *)dmin->data)->printLocate;
 50:   ((DM_Plex *)dmout->data)->printTol        = ((DM_Plex *)dmin->data)->printTol;
 51:   if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0));
 52:   PetscFunctionReturn(PETSC_SUCCESS);
 53: }

 55: /* Replace dm with the contents of ndm, and then destroy ndm
 56:    - Share the DM_Plex structure
 57:    - Share the coordinates
 58:    - Share the SF
 59: */
 60: PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm)
 61: {
 62:   PetscSF          sf;
 63:   DM               dmNew = *ndm, coordDM, coarseDM;
 64:   Vec              coords;
 65:   const PetscReal *maxCell, *Lstart, *L;
 66:   PetscInt         dim, cdim;

 68:   PetscFunctionBegin;
 69:   if (dm == dmNew) {
 70:     PetscCall(DMDestroy(ndm));
 71:     PetscFunctionReturn(PETSC_SUCCESS);
 72:   }
 73:   dm->setupcalled = dmNew->setupcalled;
 74:   if (!dm->hdr.name) {
 75:     const char *name;

 77:     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
 78:     PetscCall(PetscObjectSetName((PetscObject)dm, name));
 79:   }
 80:   PetscCall(DMGetDimension(dmNew, &dim));
 81:   PetscCall(DMSetDimension(dm, dim));
 82:   PetscCall(DMGetCoordinateDim(dmNew, &cdim));
 83:   PetscCall(DMSetCoordinateDim(dm, cdim));
 84:   PetscCall(DMGetPointSF(dmNew, &sf));
 85:   PetscCall(DMSetPointSF(dm, sf));
 86:   PetscCall(DMGetCoordinateDM(dmNew, &coordDM));
 87:   PetscCall(DMGetCoordinatesLocal(dmNew, &coords));
 88:   PetscCall(DMSetCoordinateDM(dm, coordDM));
 89:   PetscCall(DMSetCoordinatesLocal(dm, coords));
 90:   PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM));
 91:   PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords));
 92:   PetscCall(DMSetCellCoordinateDM(dm, coordDM));
 93:   PetscCall(DMSetCellCoordinatesLocal(dm, coords));
 94:   /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */
 95:   PetscCall(DMFieldDestroy(&dm->coordinates[0].field));
 96:   dm->coordinates[0].field            = dmNew->coordinates[0].field;
 97:   ((DM_Plex *)dmNew->data)->coordFunc = ((DM_Plex *)dm->data)->coordFunc;
 98:   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
 99:   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
100:   PetscCall(DMPlexGetGlobalToNaturalSF(dmNew, &sf));
101:   PetscCall(DMPlexSetGlobalToNaturalSF(dm, sf));
102:   PetscCall(DMDestroy_Plex(dm));
103:   PetscCall(DMInitialize_Plex(dm));
104:   dm->data = dmNew->data;
105:   ((DM_Plex *)dmNew->data)->refct++;
106:   {
107:     PetscInt       num_face_sfs;
108:     const PetscSF *sfs;
109:     PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &sfs));
110:     PetscCall(DMPlexSetIsoperiodicFaceSF(dm, num_face_sfs, (PetscSF *)sfs)); // for the compose function effect on dm
111:   }
112:   PetscCall(DMDestroyLabelLinkList_Internal(dm));
113:   PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
114:   PetscCall(DMGetCoarseDM(dmNew, &coarseDM));
115:   PetscCall(DMSetCoarseDM(dm, coarseDM));
116:   PetscCall(DMDestroy(ndm));
117:   PetscFunctionReturn(PETSC_SUCCESS);
118: }

120: /* Swap dm with the contents of dmNew
121:    - Swap the DM_Plex structure
122:    - Swap the coordinates
123:    - Swap the point PetscSF
124: */
125: static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
126: {
127:   DM          coordDMA, coordDMB;
128:   Vec         coordsA, coordsB;
129:   PetscSF     sfA, sfB;
130:   DMField     fieldTmp;
131:   void       *tmp;
132:   DMLabelLink listTmp;
133:   DMLabel     depthTmp;
134:   PetscInt    tmpI;

136:   PetscFunctionBegin;
137:   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
138:   PetscCall(DMGetPointSF(dmA, &sfA));
139:   PetscCall(DMGetPointSF(dmB, &sfB));
140:   PetscCall(PetscObjectReference((PetscObject)sfA));
141:   PetscCall(DMSetPointSF(dmA, sfB));
142:   PetscCall(DMSetPointSF(dmB, sfA));
143:   PetscCall(PetscObjectDereference((PetscObject)sfA));

145:   PetscCall(DMGetCoordinateDM(dmA, &coordDMA));
146:   PetscCall(DMGetCoordinateDM(dmB, &coordDMB));
147:   PetscCall(PetscObjectReference((PetscObject)coordDMA));
148:   PetscCall(DMSetCoordinateDM(dmA, coordDMB));
149:   PetscCall(DMSetCoordinateDM(dmB, coordDMA));
150:   PetscCall(PetscObjectDereference((PetscObject)coordDMA));

152:   PetscCall(DMGetCoordinatesLocal(dmA, &coordsA));
153:   PetscCall(DMGetCoordinatesLocal(dmB, &coordsB));
154:   PetscCall(PetscObjectReference((PetscObject)coordsA));
155:   PetscCall(DMSetCoordinatesLocal(dmA, coordsB));
156:   PetscCall(DMSetCoordinatesLocal(dmB, coordsA));
157:   PetscCall(PetscObjectDereference((PetscObject)coordsA));

159:   PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA));
160:   PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB));
161:   PetscCall(PetscObjectReference((PetscObject)coordDMA));
162:   PetscCall(DMSetCellCoordinateDM(dmA, coordDMB));
163:   PetscCall(DMSetCellCoordinateDM(dmB, coordDMA));
164:   PetscCall(PetscObjectDereference((PetscObject)coordDMA));

166:   PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA));
167:   PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB));
168:   PetscCall(PetscObjectReference((PetscObject)coordsA));
169:   PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB));
170:   PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA));
171:   PetscCall(PetscObjectDereference((PetscObject)coordsA));

173:   fieldTmp                  = dmA->coordinates[0].field;
174:   dmA->coordinates[0].field = dmB->coordinates[0].field;
175:   dmB->coordinates[0].field = fieldTmp;
176:   fieldTmp                  = dmA->coordinates[1].field;
177:   dmA->coordinates[1].field = dmB->coordinates[1].field;
178:   dmB->coordinates[1].field = fieldTmp;
179:   tmp                       = dmA->data;
180:   dmA->data                 = dmB->data;
181:   dmB->data                 = tmp;
182:   listTmp                   = dmA->labels;
183:   dmA->labels               = dmB->labels;
184:   dmB->labels               = listTmp;
185:   depthTmp                  = dmA->depthLabel;
186:   dmA->depthLabel           = dmB->depthLabel;
187:   dmB->depthLabel           = depthTmp;
188:   depthTmp                  = dmA->celltypeLabel;
189:   dmA->celltypeLabel        = dmB->celltypeLabel;
190:   dmB->celltypeLabel        = depthTmp;
191:   tmpI                      = dmA->levelup;
192:   dmA->levelup              = dmB->levelup;
193:   dmB->levelup              = tmpI;
194:   PetscFunctionReturn(PETSC_SUCCESS);
195: }

197: PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm)
198: {
199:   DM idm;

201:   PetscFunctionBegin;
202:   PetscCall(DMPlexInterpolate(dm, &idm));
203:   PetscCall(DMPlexCopyCoordinates(dm, idm));
204:   PetscCall(DMPlexReplace_Internal(dm, &idm));
205:   PetscFunctionReturn(PETSC_SUCCESS);
206: }

208: /*@C
209:   DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates

211:   Collective

213:   Input Parameters:
214: + dm        - The `DMPLEX`
215: . degree    - The degree of the finite element or `PETSC_DECIDE`
216: . project   - Flag to project current coordinates into the space
217: - coordFunc - An optional function to map new points from refinement to the surface

219:   Level: advanced

221: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPointFunc`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()`
222: @*/
223: PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscBool project, PetscPointFunc coordFunc)
224: {
225:   DM_Plex *mesh = (DM_Plex *)dm->data;
226:   PetscFE  fe   = NULL;
227:   DM       cdm;
228:   PetscInt dim, dE, qorder, height;

230:   PetscFunctionBegin;
231:   PetscCall(DMGetDimension(dm, &dim));
232:   PetscCall(DMGetCoordinateDim(dm, &dE));
233:   qorder = degree;
234:   PetscCall(DMGetCoordinateDM(dm, &cdm));
235:   PetscObjectOptionsBegin((PetscObject)cdm);
236:   PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0));
237:   PetscOptionsEnd();
238:   PetscCall(DMPlexGetVTKCellHeight(dm, &height));
239:   if (degree >= 0) {
240:     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
241:     PetscInt       cStart, cEnd, gct;

243:     PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
244:     if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct));
245:     gct = (PetscInt)ct;
246:     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm)));
247:     ct = (DMPolytopeType)gct;
248:     // Work around current bug in PetscDualSpaceSetUp_Lagrange()
249:     //   Can be seen in plex_tutorials-ex10_1
250:     if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe));
251:   }
252:   PetscCall(DMSetCoordinateDisc(dm, fe, project));
253:   PetscCall(PetscFEDestroy(&fe));
254:   mesh->coordFunc = coordFunc;
255:   PetscFunctionReturn(PETSC_SUCCESS);
256: }

258: /*@
259:   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.

261:   Collective

263:   Input Parameters:
264: + comm            - The communicator for the `DM` object
265: . dim             - The spatial dimension
266: . simplex         - Flag for simplicial cells, otherwise they are tensor product cells
267: . interpolate     - Flag to create intermediate mesh pieces (edges, faces)
268: - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell

270:   Output Parameter:
271: . newdm - The `DM` object

273:   Level: beginner

275: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()`
276: @*/
277: PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm)
278: {
279:   DM          dm;
280:   PetscMPIInt rank;

282:   PetscFunctionBegin;
283:   PetscCall(DMCreate(comm, &dm));
284:   PetscCall(DMSetType(dm, DMPLEX));
285:   PetscCall(DMSetDimension(dm, dim));
286:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
287:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
288:   switch (dim) {
289:   case 2:
290:     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular"));
291:     else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral"));
292:     break;
293:   case 3:
294:     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral"));
295:     else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral"));
296:     break;
297:   default:
298:     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
299:   }
300:   if (rank) {
301:     PetscInt numPoints[2] = {0, 0};
302:     PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL));
303:   } else {
304:     switch (dim) {
305:     case 2:
306:       if (simplex) {
307:         PetscInt    numPoints[2]        = {4, 2};
308:         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
309:         PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
310:         PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
311:         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};

313:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
314:       } else {
315:         PetscInt    numPoints[2]        = {6, 2};
316:         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
317:         PetscInt    cones[8]            = {2, 3, 4, 5, 3, 6, 7, 4};
318:         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
319:         PetscScalar vertexCoords[12]    = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5};

321:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
322:       }
323:       break;
324:     case 3:
325:       if (simplex) {
326:         PetscInt    numPoints[2]        = {5, 2};
327:         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
328:         PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
329:         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
330:         PetscScalar vertexCoords[15]    = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};

332:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
333:       } else {
334:         PetscInt    numPoints[2]         = {12, 2};
335:         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
336:         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
337:         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
338:         PetscScalar vertexCoords[36]     = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5};

340:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
341:       }
342:       break;
343:     default:
344:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
345:     }
346:   }
347:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
348:   *newdm = dm;
349:   if (refinementLimit > 0.0) {
350:     DM          rdm;
351:     const char *name;

353:     PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE));
354:     PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit));
355:     PetscCall(DMRefine(*newdm, comm, &rdm));
356:     PetscCall(PetscObjectGetName((PetscObject)*newdm, &name));
357:     PetscCall(PetscObjectSetName((PetscObject)rdm, name));
358:     PetscCall(DMDestroy(newdm));
359:     *newdm = rdm;
360:   }
361:   if (interpolate) {
362:     DM idm;

364:     PetscCall(DMPlexInterpolate(*newdm, &idm));
365:     PetscCall(DMDestroy(newdm));
366:     *newdm = idm;
367:   }
368:   PetscFunctionReturn(PETSC_SUCCESS);
369: }

371: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
372: {
373:   const PetscInt numVertices    = 2;
374:   PetscInt       markerRight    = 1;
375:   PetscInt       markerLeft     = 1;
376:   PetscBool      markerSeparate = PETSC_FALSE;
377:   Vec            coordinates;
378:   PetscSection   coordSection;
379:   PetscScalar   *coords;
380:   PetscInt       coordSize;
381:   PetscMPIInt    rank;
382:   PetscInt       cdim = 1, v;

384:   PetscFunctionBegin;
385:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
386:   if (markerSeparate) {
387:     markerRight = 2;
388:     markerLeft  = 1;
389:   }
390:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
391:   if (rank == 0) {
392:     PetscCall(DMPlexSetChart(dm, 0, numVertices));
393:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
394:     PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft));
395:     PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight));
396:   }
397:   PetscCall(DMPlexSymmetrize(dm));
398:   PetscCall(DMPlexStratify(dm));
399:   /* Build coordinates */
400:   PetscCall(DMSetCoordinateDim(dm, cdim));
401:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
402:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
403:   PetscCall(PetscSectionSetChart(coordSection, 0, numVertices));
404:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
405:   for (v = 0; v < numVertices; ++v) {
406:     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
407:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
408:   }
409:   PetscCall(PetscSectionSetUp(coordSection));
410:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
411:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
412:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
413:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
414:   PetscCall(VecSetBlockSize(coordinates, cdim));
415:   PetscCall(VecSetType(coordinates, VECSTANDARD));
416:   PetscCall(VecGetArray(coordinates, &coords));
417:   coords[0] = lower[0];
418:   coords[1] = upper[0];
419:   PetscCall(VecRestoreArray(coordinates, &coords));
420:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
421:   PetscCall(VecDestroy(&coordinates));
422:   PetscFunctionReturn(PETSC_SUCCESS);
423: }

425: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
426: {
427:   const PetscInt numVertices    = (edges[0] + 1) * (edges[1] + 1);
428:   const PetscInt numEdges       = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1];
429:   PetscInt       markerTop      = 1;
430:   PetscInt       markerBottom   = 1;
431:   PetscInt       markerRight    = 1;
432:   PetscInt       markerLeft     = 1;
433:   PetscBool      markerSeparate = PETSC_FALSE;
434:   Vec            coordinates;
435:   PetscSection   coordSection;
436:   PetscScalar   *coords;
437:   PetscInt       coordSize;
438:   PetscMPIInt    rank;
439:   PetscInt       v, vx, vy;

441:   PetscFunctionBegin;
442:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
443:   if (markerSeparate) {
444:     markerTop    = 3;
445:     markerBottom = 1;
446:     markerRight  = 2;
447:     markerLeft   = 4;
448:   }
449:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
450:   if (rank == 0) {
451:     PetscInt e, ex, ey;

453:     PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices));
454:     for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
455:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
456:     for (vx = 0; vx <= edges[0]; vx++) {
457:       for (ey = 0; ey < edges[1]; ey++) {
458:         PetscInt edge   = vx * edges[1] + ey + edges[0] * (edges[1] + 1);
459:         PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges;
460:         PetscInt cone[2];

462:         cone[0] = vertex;
463:         cone[1] = vertex + edges[0] + 1;
464:         PetscCall(DMPlexSetCone(dm, edge, cone));
465:         if (vx == edges[0]) {
466:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
467:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
468:           if (ey == edges[1] - 1) {
469:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
470:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight));
471:           }
472:         } else if (vx == 0) {
473:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
474:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
475:           if (ey == edges[1] - 1) {
476:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
477:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft));
478:           }
479:         }
480:       }
481:     }
482:     for (vy = 0; vy <= edges[1]; vy++) {
483:       for (ex = 0; ex < edges[0]; ex++) {
484:         PetscInt edge   = vy * edges[0] + ex;
485:         PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges;
486:         PetscInt cone[2];

488:         cone[0] = vertex;
489:         cone[1] = vertex + 1;
490:         PetscCall(DMPlexSetCone(dm, edge, cone));
491:         if (vy == edges[1]) {
492:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
493:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
494:           if (ex == edges[0] - 1) {
495:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
496:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop));
497:           }
498:         } else if (vy == 0) {
499:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
500:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
501:           if (ex == edges[0] - 1) {
502:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
503:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom));
504:           }
505:         }
506:       }
507:     }
508:   }
509:   PetscCall(DMPlexSymmetrize(dm));
510:   PetscCall(DMPlexStratify(dm));
511:   /* Build coordinates */
512:   PetscCall(DMSetCoordinateDim(dm, 2));
513:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
514:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
515:   PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices));
516:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
517:   for (v = numEdges; v < numEdges + numVertices; ++v) {
518:     PetscCall(PetscSectionSetDof(coordSection, v, 2));
519:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
520:   }
521:   PetscCall(PetscSectionSetUp(coordSection));
522:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
523:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
524:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
525:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
526:   PetscCall(VecSetBlockSize(coordinates, 2));
527:   PetscCall(VecSetType(coordinates, VECSTANDARD));
528:   PetscCall(VecGetArray(coordinates, &coords));
529:   for (vy = 0; vy <= edges[1]; ++vy) {
530:     for (vx = 0; vx <= edges[0]; ++vx) {
531:       coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx;
532:       coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy;
533:     }
534:   }
535:   PetscCall(VecRestoreArray(coordinates, &coords));
536:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
537:   PetscCall(VecDestroy(&coordinates));
538:   PetscFunctionReturn(PETSC_SUCCESS);
539: }

541: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
542: {
543:   PetscInt     vertices[3], numVertices;
544:   PetscInt     numFaces       = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2];
545:   PetscInt     markerTop      = 1;
546:   PetscInt     markerBottom   = 1;
547:   PetscInt     markerFront    = 1;
548:   PetscInt     markerBack     = 1;
549:   PetscInt     markerRight    = 1;
550:   PetscInt     markerLeft     = 1;
551:   PetscBool    markerSeparate = PETSC_FALSE;
552:   Vec          coordinates;
553:   PetscSection coordSection;
554:   PetscScalar *coords;
555:   PetscInt     coordSize;
556:   PetscMPIInt  rank;
557:   PetscInt     v, vx, vy, vz;
558:   PetscInt     voffset, iface = 0, cone[4];

560:   PetscFunctionBegin;
561:   PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side");
562:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
563:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
564:   if (markerSeparate) {
565:     markerBottom = 1;
566:     markerTop    = 2;
567:     markerFront  = 3;
568:     markerBack   = 4;
569:     markerRight  = 5;
570:     markerLeft   = 6;
571:   }
572:   vertices[0] = faces[0] + 1;
573:   vertices[1] = faces[1] + 1;
574:   vertices[2] = faces[2] + 1;
575:   numVertices = vertices[0] * vertices[1] * vertices[2];
576:   if (rank == 0) {
577:     PetscInt f;

579:     PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices));
580:     for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
581:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */

583:     /* Side 0 (Top) */
584:     for (vy = 0; vy < faces[1]; vy++) {
585:       for (vx = 0; vx < faces[0]; vx++) {
586:         voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx;
587:         cone[0] = voffset;
588:         cone[1] = voffset + 1;
589:         cone[2] = voffset + vertices[0] + 1;
590:         cone[3] = voffset + vertices[0];
591:         PetscCall(DMPlexSetCone(dm, iface, cone));
592:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop));
593:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop));
594:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop));
595:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop));
596:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop));
597:         iface++;
598:       }
599:     }

601:     /* Side 1 (Bottom) */
602:     for (vy = 0; vy < faces[1]; vy++) {
603:       for (vx = 0; vx < faces[0]; vx++) {
604:         voffset = numFaces + vy * (faces[0] + 1) + vx;
605:         cone[0] = voffset + 1;
606:         cone[1] = voffset;
607:         cone[2] = voffset + vertices[0];
608:         cone[3] = voffset + vertices[0] + 1;
609:         PetscCall(DMPlexSetCone(dm, iface, cone));
610:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom));
611:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom));
612:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom));
613:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom));
614:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom));
615:         iface++;
616:       }
617:     }

619:     /* Side 2 (Front) */
620:     for (vz = 0; vz < faces[2]; vz++) {
621:       for (vx = 0; vx < faces[0]; vx++) {
622:         voffset = numFaces + vz * vertices[0] * vertices[1] + vx;
623:         cone[0] = voffset;
624:         cone[1] = voffset + 1;
625:         cone[2] = voffset + vertices[0] * vertices[1] + 1;
626:         cone[3] = voffset + vertices[0] * vertices[1];
627:         PetscCall(DMPlexSetCone(dm, iface, cone));
628:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront));
629:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront));
630:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront));
631:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront));
632:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront));
633:         iface++;
634:       }
635:     }

637:     /* Side 3 (Back) */
638:     for (vz = 0; vz < faces[2]; vz++) {
639:       for (vx = 0; vx < faces[0]; vx++) {
640:         voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx;
641:         cone[0] = voffset + vertices[0] * vertices[1];
642:         cone[1] = voffset + vertices[0] * vertices[1] + 1;
643:         cone[2] = voffset + 1;
644:         cone[3] = voffset;
645:         PetscCall(DMPlexSetCone(dm, iface, cone));
646:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack));
647:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack));
648:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack));
649:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack));
650:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack));
651:         iface++;
652:       }
653:     }

655:     /* Side 4 (Left) */
656:     for (vz = 0; vz < faces[2]; vz++) {
657:       for (vy = 0; vy < faces[1]; vy++) {
658:         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0];
659:         cone[0] = voffset;
660:         cone[1] = voffset + vertices[0] * vertices[1];
661:         cone[2] = voffset + vertices[0] * vertices[1] + vertices[0];
662:         cone[3] = voffset + vertices[0];
663:         PetscCall(DMPlexSetCone(dm, iface, cone));
664:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft));
665:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft));
666:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft));
667:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft));
668:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft));
669:         iface++;
670:       }
671:     }

673:     /* Side 5 (Right) */
674:     for (vz = 0; vz < faces[2]; vz++) {
675:       for (vy = 0; vy < faces[1]; vy++) {
676:         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0];
677:         cone[0] = voffset + vertices[0] * vertices[1];
678:         cone[1] = voffset;
679:         cone[2] = voffset + vertices[0];
680:         cone[3] = voffset + vertices[0] * vertices[1] + vertices[0];
681:         PetscCall(DMPlexSetCone(dm, iface, cone));
682:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight));
683:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight));
684:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight));
685:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight));
686:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight));
687:         iface++;
688:       }
689:     }
690:   }
691:   PetscCall(DMPlexSymmetrize(dm));
692:   PetscCall(DMPlexStratify(dm));
693:   /* Build coordinates */
694:   PetscCall(DMSetCoordinateDim(dm, 3));
695:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
696:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
697:   PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices));
698:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
699:   for (v = numFaces; v < numFaces + numVertices; ++v) {
700:     PetscCall(PetscSectionSetDof(coordSection, v, 3));
701:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
702:   }
703:   PetscCall(PetscSectionSetUp(coordSection));
704:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
705:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
706:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
707:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
708:   PetscCall(VecSetBlockSize(coordinates, 3));
709:   PetscCall(VecSetType(coordinates, VECSTANDARD));
710:   PetscCall(VecGetArray(coordinates, &coords));
711:   for (vz = 0; vz <= faces[2]; ++vz) {
712:     for (vy = 0; vy <= faces[1]; ++vy) {
713:       for (vx = 0; vx <= faces[0]; ++vx) {
714:         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx;
715:         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy;
716:         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz;
717:       }
718:     }
719:   }
720:   PetscCall(VecRestoreArray(coordinates, &coords));
721:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
722:   PetscCall(VecDestroy(&coordinates));
723:   PetscFunctionReturn(PETSC_SUCCESS);
724: }

726: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate)
727: {
728:   PetscFunctionBegin;
730:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
731:   PetscCall(DMSetDimension(dm, dim - 1));
732:   PetscCall(DMSetCoordinateDim(dm, dim));
733:   switch (dim) {
734:   case 1:
735:     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces));
736:     break;
737:   case 2:
738:     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces));
739:     break;
740:   case 3:
741:     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces));
742:     break;
743:   default:
744:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim);
745:   }
746:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
747:   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
748:   PetscFunctionReturn(PETSC_SUCCESS);
749: }

751: /*@C
752:   DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra).

754:   Collective

756:   Input Parameters:
757: + comm        - The communicator for the `DM` object
758: . dim         - The spatial dimension of the box, so the resulting mesh is has dimension `dim`-1
759: . faces       - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
760: . lower       - The lower left corner, or `NULL` for (0, 0, 0)
761: . upper       - The upper right corner, or `NULL` for (1, 1, 1)
762: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

764:   Output Parameter:
765: . dm - The `DM` object

767:   Level: beginner

769: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()`
770: @*/
771: PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm)
772: {
773:   PetscInt  fac[3] = {1, 1, 1};
774:   PetscReal low[3] = {0, 0, 0};
775:   PetscReal upp[3] = {1, 1, 1};

777:   PetscFunctionBegin;
778:   PetscCall(DMCreate(comm, dm));
779:   PetscCall(DMSetType(*dm, DMPLEX));
780:   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate));
781:   PetscFunctionReturn(PETSC_SUCCESS);
782: }

784: static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd)
785: {
786:   PetscInt     i, fStart, fEnd, numCells = 0, numVerts = 0;
787:   PetscInt     numPoints[2], *coneSize, *cones, *coneOrientations;
788:   PetscScalar *vertexCoords;
789:   PetscReal    L, maxCell;
790:   PetscBool    markerSeparate = PETSC_FALSE;
791:   PetscInt     markerLeft = 1, faceMarkerLeft = 1;
792:   PetscInt     markerRight = 1, faceMarkerRight = 2;
793:   PetscBool    wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE;
794:   PetscMPIInt  rank;

796:   PetscFunctionBegin;
797:   PetscAssertPointer(dm, 1);

799:   PetscCall(DMSetDimension(dm, 1));
800:   PetscCall(DMCreateLabel(dm, "marker"));
801:   PetscCall(DMCreateLabel(dm, "Face Sets"));

803:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
804:   if (rank == 0) numCells = segments;
805:   if (rank == 0) numVerts = segments + (wrap ? 0 : 1);

807:   numPoints[0] = numVerts;
808:   numPoints[1] = numCells;
809:   PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords));
810:   PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts));
811:   for (i = 0; i < numCells; ++i) coneSize[i] = 2;
812:   for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0;
813:   for (i = 0; i < numCells; ++i) {
814:     cones[2 * i]     = numCells + i % numVerts;
815:     cones[2 * i + 1] = numCells + (i + 1) % numVerts;
816:   }
817:   for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells);
818:   PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
819:   PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords));

821:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
822:   if (markerSeparate) {
823:     markerLeft  = faceMarkerLeft;
824:     markerRight = faceMarkerRight;
825:   }
826:   if (!wrap && rank == 0) {
827:     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
828:     PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft));
829:     PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight));
830:     PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft));
831:     PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight));
832:   }
833:   if (wrap) {
834:     L       = upper - lower;
835:     maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments));
836:     PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L));
837:   }
838:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
839:   PetscFunctionReturn(PETSC_SUCCESS);
840: }

842: static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
843: {
844:   DM      boundary, vol;
845:   DMLabel bdlabel;

847:   PetscFunctionBegin;
848:   PetscAssertPointer(dm, 1);
849:   for (PetscInt i = 0; i < dim; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity is not supported for simplex meshes");
850:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary));
851:   PetscCall(DMSetType(boundary, DMPLEX));
852:   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE));
853:   PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol));
854:   PetscCall(DMGetLabel(vol, "marker", &bdlabel));
855:   if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel));
856:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol));
857:   PetscCall(DMPlexReplace_Internal(dm, &vol));
858:   PetscCall(DMDestroy(&boundary));
859:   PetscFunctionReturn(PETSC_SUCCESS);
860: }

862: static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
863: {
864:   DMLabel     cutLabel  = NULL;
865:   PetscInt    markerTop = 1, faceMarkerTop = 1;
866:   PetscInt    markerBottom = 1, faceMarkerBottom = 1;
867:   PetscInt    markerFront = 1, faceMarkerFront = 1;
868:   PetscInt    markerBack = 1, faceMarkerBack = 1;
869:   PetscInt    markerRight = 1, faceMarkerRight = 1;
870:   PetscInt    markerLeft = 1, faceMarkerLeft = 1;
871:   PetscInt    dim;
872:   PetscBool   markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
873:   PetscMPIInt rank;

875:   PetscFunctionBegin;
876:   PetscCall(DMGetDimension(dm, &dim));
877:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
878:   PetscCall(DMCreateLabel(dm, "marker"));
879:   PetscCall(DMCreateLabel(dm, "Face Sets"));
880:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
881:   if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST || bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST || bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) {
882:     if (cutMarker) {
883:       PetscCall(DMCreateLabel(dm, "periodic_cut"));
884:       PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
885:     }
886:   }
887:   switch (dim) {
888:   case 2:
889:     faceMarkerTop    = 3;
890:     faceMarkerBottom = 1;
891:     faceMarkerRight  = 2;
892:     faceMarkerLeft   = 4;
893:     break;
894:   case 3:
895:     faceMarkerBottom = 1;
896:     faceMarkerTop    = 2;
897:     faceMarkerFront  = 3;
898:     faceMarkerBack   = 4;
899:     faceMarkerRight  = 5;
900:     faceMarkerLeft   = 6;
901:     break;
902:   default:
903:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
904:   }
905:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
906:   if (markerSeparate) {
907:     markerBottom = faceMarkerBottom;
908:     markerTop    = faceMarkerTop;
909:     markerFront  = faceMarkerFront;
910:     markerBack   = faceMarkerBack;
911:     markerRight  = faceMarkerRight;
912:     markerLeft   = faceMarkerLeft;
913:   }
914:   {
915:     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
916:     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
917:     const PetscInt numZEdges    = rank == 0 ? edges[2] : 0;
918:     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0;
919:     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0;
920:     const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0;
921:     const PetscInt numCells     = numXEdges * numYEdges * numZEdges;
922:     const PetscInt numXFaces    = numYEdges * numZEdges;
923:     const PetscInt numYFaces    = numXEdges * numZEdges;
924:     const PetscInt numZFaces    = numXEdges * numYEdges;
925:     const PetscInt numTotXFaces = numXVertices * numXFaces;
926:     const PetscInt numTotYFaces = numYVertices * numYFaces;
927:     const PetscInt numTotZFaces = numZVertices * numZFaces;
928:     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
929:     const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices;
930:     const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices;
931:     const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices;
932:     const PetscInt numVertices  = numXVertices * numYVertices * numZVertices;
933:     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
934:     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
935:     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
936:     const PetscInt firstYFace   = firstXFace + numTotXFaces;
937:     const PetscInt firstZFace   = firstYFace + numTotYFaces;
938:     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
939:     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
940:     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
941:     Vec            coordinates;
942:     PetscSection   coordSection;
943:     PetscScalar   *coords;
944:     PetscInt       coordSize;
945:     PetscInt       v, vx, vy, vz;
946:     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;

948:     PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices));
949:     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
950:     for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
951:     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
952:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
953:     /* Build cells */
954:     for (fz = 0; fz < numZEdges; ++fz) {
955:       for (fy = 0; fy < numYEdges; ++fy) {
956:         for (fx = 0; fx < numXEdges; ++fx) {
957:           PetscInt cell  = (fz * numYEdges + fy) * numXEdges + fx;
958:           PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
959:           PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices);
960:           PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
961:           PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices);
962:           PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
963:           PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices);
964:           /* B,  T,  F,  K,  R,  L */
965:           PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */
966:           PetscInt cone[6];

968:           /* no boundary twisting in 3D */
969:           cone[0] = faceB;
970:           cone[1] = faceT;
971:           cone[2] = faceF;
972:           cone[3] = faceK;
973:           cone[4] = faceR;
974:           cone[5] = faceL;
975:           PetscCall(DMPlexSetCone(dm, cell, cone));
976:           PetscCall(DMPlexSetConeOrientation(dm, cell, ornt));
977:           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
978:           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
979:           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
980:         }
981:       }
982:     }
983:     /* Build x faces */
984:     for (fz = 0; fz < numZEdges; ++fz) {
985:       for (fy = 0; fy < numYEdges; ++fy) {
986:         for (fx = 0; fx < numXVertices; ++fx) {
987:           PetscInt face    = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
988:           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
989:           PetscInt edgeR   = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz;
990:           PetscInt edgeB   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
991:           PetscInt edgeT   = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy;
992:           PetscInt ornt[4] = {0, 0, -1, -1};
993:           PetscInt cone[4];

995:           if (dim == 3) {
996:             /* markers */
997:             if (bdX != DM_BOUNDARY_PERIODIC) {
998:               if (fx == numXVertices - 1) {
999:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight));
1000:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight));
1001:               } else if (fx == 0) {
1002:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft));
1003:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft));
1004:               }
1005:             }
1006:           }
1007:           cone[0] = edgeB;
1008:           cone[1] = edgeR;
1009:           cone[2] = edgeT;
1010:           cone[3] = edgeL;
1011:           PetscCall(DMPlexSetCone(dm, face, cone));
1012:           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1013:         }
1014:       }
1015:     }
1016:     /* Build y faces */
1017:     for (fz = 0; fz < numZEdges; ++fz) {
1018:       for (fx = 0; fx < numXEdges; ++fx) {
1019:         for (fy = 0; fy < numYVertices; ++fy) {
1020:           PetscInt face    = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
1021:           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
1022:           PetscInt edgeR   = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz;
1023:           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1024:           PetscInt edgeT   = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx;
1025:           PetscInt ornt[4] = {0, 0, -1, -1};
1026:           PetscInt cone[4];

1028:           if (dim == 3) {
1029:             /* markers */
1030:             if (bdY != DM_BOUNDARY_PERIODIC) {
1031:               if (fy == numYVertices - 1) {
1032:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack));
1033:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack));
1034:               } else if (fy == 0) {
1035:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront));
1036:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront));
1037:               }
1038:             }
1039:           }
1040:           cone[0] = edgeB;
1041:           cone[1] = edgeR;
1042:           cone[2] = edgeT;
1043:           cone[3] = edgeL;
1044:           PetscCall(DMPlexSetCone(dm, face, cone));
1045:           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1046:         }
1047:       }
1048:     }
1049:     /* Build z faces */
1050:     for (fy = 0; fy < numYEdges; ++fy) {
1051:       for (fx = 0; fx < numXEdges; ++fx) {
1052:         for (fz = 0; fz < numZVertices; fz++) {
1053:           PetscInt face    = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
1054:           PetscInt edgeL   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
1055:           PetscInt edgeR   = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy;
1056:           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1057:           PetscInt edgeT   = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx;
1058:           PetscInt ornt[4] = {0, 0, -1, -1};
1059:           PetscInt cone[4];

1061:           if (dim == 2) {
1062:             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) {
1063:               edgeR += numYEdges - 1 - 2 * fy;
1064:               ornt[1] = -1;
1065:             }
1066:             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) {
1067:               edgeT += numXEdges - 1 - 2 * fx;
1068:               ornt[2] = 0;
1069:             }
1070:             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1071:             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1072:           } else {
1073:             /* markers */
1074:             if (bdZ != DM_BOUNDARY_PERIODIC) {
1075:               if (fz == numZVertices - 1) {
1076:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop));
1077:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop));
1078:               } else if (fz == 0) {
1079:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom));
1080:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom));
1081:               }
1082:             }
1083:           }
1084:           cone[0] = edgeB;
1085:           cone[1] = edgeR;
1086:           cone[2] = edgeT;
1087:           cone[3] = edgeL;
1088:           PetscCall(DMPlexSetCone(dm, face, cone));
1089:           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1090:         }
1091:       }
1092:     }
1093:     /* Build Z edges*/
1094:     for (vy = 0; vy < numYVertices; vy++) {
1095:       for (vx = 0; vx < numXVertices; vx++) {
1096:         for (ez = 0; ez < numZEdges; ez++) {
1097:           const PetscInt edge    = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez;
1098:           const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx;
1099:           const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx;
1100:           PetscInt       cone[2];

1102:           cone[0] = vertexB;
1103:           cone[1] = vertexT;
1104:           PetscCall(DMPlexSetCone(dm, edge, cone));
1105:           if (dim == 3) {
1106:             if (bdX != DM_BOUNDARY_PERIODIC) {
1107:               if (vx == numXVertices - 1) {
1108:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1109:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1110:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1111:               } else if (vx == 0) {
1112:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1113:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1114:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1115:               }
1116:             }
1117:             if (bdY != DM_BOUNDARY_PERIODIC) {
1118:               if (vy == numYVertices - 1) {
1119:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1120:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1121:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1122:               } else if (vy == 0) {
1123:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1124:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1125:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1126:               }
1127:             }
1128:           }
1129:         }
1130:       }
1131:     }
1132:     /* Build Y edges*/
1133:     for (vz = 0; vz < numZVertices; vz++) {
1134:       for (vx = 0; vx < numXVertices; vx++) {
1135:         for (ey = 0; ey < numYEdges; ey++) {
1136:           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx;
1137:           const PetscInt edge    = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey;
1138:           const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx;
1139:           const PetscInt vertexK = firstVertex + nextv;
1140:           PetscInt       cone[2];

1142:           cone[0] = vertexF;
1143:           cone[1] = vertexK;
1144:           PetscCall(DMPlexSetCone(dm, edge, cone));
1145:           if (dim == 2) {
1146:             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
1147:               if (vx == numXVertices - 1) {
1148:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
1149:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1150:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1151:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1152:               } else if (vx == 0) {
1153:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
1154:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1155:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1156:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1157:               }
1158:             } else {
1159:               if (vx == 0 && cutLabel) {
1160:                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1161:                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1162:                 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1163:               }
1164:             }
1165:           } else {
1166:             if (bdX != DM_BOUNDARY_PERIODIC) {
1167:               if (vx == numXVertices - 1) {
1168:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1169:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1170:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1171:               } else if (vx == 0) {
1172:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1173:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1174:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1175:               }
1176:             }
1177:             if (bdZ != DM_BOUNDARY_PERIODIC) {
1178:               if (vz == numZVertices - 1) {
1179:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1180:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1181:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1182:               } else if (vz == 0) {
1183:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1184:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1185:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1186:               }
1187:             }
1188:           }
1189:         }
1190:       }
1191:     }
1192:     /* Build X edges*/
1193:     for (vz = 0; vz < numZVertices; vz++) {
1194:       for (vy = 0; vy < numYVertices; vy++) {
1195:         for (ex = 0; ex < numXEdges; ex++) {
1196:           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices;
1197:           const PetscInt edge    = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex;
1198:           const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex;
1199:           const PetscInt vertexR = firstVertex + nextv;
1200:           PetscInt       cone[2];

1202:           cone[0] = vertexL;
1203:           cone[1] = vertexR;
1204:           PetscCall(DMPlexSetCone(dm, edge, cone));
1205:           if (dim == 2) {
1206:             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
1207:               if (vy == numYVertices - 1) {
1208:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
1209:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1210:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1211:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1212:               } else if (vy == 0) {
1213:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
1214:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1215:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1216:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1217:               }
1218:             } else {
1219:               if (vy == 0 && cutLabel) {
1220:                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1221:                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1222:                 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1223:               }
1224:             }
1225:           } else {
1226:             if (bdY != DM_BOUNDARY_PERIODIC) {
1227:               if (vy == numYVertices - 1) {
1228:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1229:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1230:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1231:               } else if (vy == 0) {
1232:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1233:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1234:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1235:               }
1236:             }
1237:             if (bdZ != DM_BOUNDARY_PERIODIC) {
1238:               if (vz == numZVertices - 1) {
1239:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1240:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1241:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1242:               } else if (vz == 0) {
1243:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1244:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1245:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1246:               }
1247:             }
1248:           }
1249:         }
1250:       }
1251:     }
1252:     PetscCall(DMPlexSymmetrize(dm));
1253:     PetscCall(DMPlexStratify(dm));
1254:     /* Build coordinates */
1255:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1256:     PetscCall(PetscSectionSetNumFields(coordSection, 1));
1257:     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1258:     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
1259:     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
1260:       PetscCall(PetscSectionSetDof(coordSection, v, dim));
1261:       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1262:     }
1263:     PetscCall(PetscSectionSetUp(coordSection));
1264:     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1265:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1266:     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1267:     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1268:     PetscCall(VecSetBlockSize(coordinates, dim));
1269:     PetscCall(VecSetType(coordinates, VECSTANDARD));
1270:     PetscCall(VecGetArray(coordinates, &coords));
1271:     for (vz = 0; vz < numZVertices; ++vz) {
1272:       for (vy = 0; vy < numYVertices; ++vy) {
1273:         for (vx = 0; vx < numXVertices; ++vx) {
1274:           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
1275:           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1276:           if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz;
1277:         }
1278:       }
1279:     }
1280:     PetscCall(VecRestoreArray(coordinates, &coords));
1281:     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1282:     PetscCall(VecDestroy(&coordinates));
1283:   }
1284:   PetscFunctionReturn(PETSC_SUCCESS);
1285: }

1287: static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1288: {
1289:   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1290:   PetscInt       fac[3] = {0, 0, 0}, d;

1292:   PetscFunctionBegin;
1293:   PetscAssertPointer(dm, 1);
1295:   PetscCall(DMSetDimension(dm, dim));
1296:   for (d = 0; d < dim; ++d) {
1297:     fac[d] = faces[d];
1298:     bdt[d] = periodicity[d];
1299:   }
1300:   PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2]));
1301:   if (periodicity[0] == DM_BOUNDARY_PERIODIC || periodicity[0] == DM_BOUNDARY_TWIST || periodicity[1] == DM_BOUNDARY_PERIODIC || periodicity[1] == DM_BOUNDARY_TWIST || (dim > 2 && (periodicity[2] == DM_BOUNDARY_PERIODIC || periodicity[2] == DM_BOUNDARY_TWIST))) {
1302:     PetscReal L[3]       = {-1., -1., 0.};
1303:     PetscReal maxCell[3] = {-1., -1., 0.};

1305:     for (d = 0; d < dim; ++d) {
1306:       if (periodicity[d] != DM_BOUNDARY_NONE) {
1307:         L[d]       = upper[d] - lower[d];
1308:         maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d]));
1309:       }
1310:     }
1311:     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1312:   }
1313:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1314:   PetscFunctionReturn(PETSC_SUCCESS);
1315: }

1317: static PetscErrorCode DMPlexCreateBoxMesh_Internal(DM dm, DMPlexShape shape, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
1318: {
1319:   PetscFunctionBegin;
1320:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1321:   if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1322:   else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0]));
1323:   else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1324:   else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity));
1325:   if (!interpolate && dim > 1 && !simplex) {
1326:     DM udm;

1328:     PetscCall(DMPlexUninterpolate(dm, &udm));
1329:     PetscCall(DMPlexCopyCoordinates(dm, udm));
1330:     PetscCall(DMPlexReplace_Internal(dm, &udm));
1331:   }
1332:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
1333:   PetscFunctionReturn(PETSC_SUCCESS);
1334: }

1336: /*@C
1337:   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra).

1339:   Collective

1341:   Input Parameters:
1342: + comm        - The communicator for the `DM` object
1343: . dim         - The spatial dimension
1344: . simplex     - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells
1345: . faces       - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1346: . lower       - The lower left corner, or `NULL` for (0, 0, 0)
1347: . upper       - The upper right corner, or `NULL` for (1, 1, 1)
1348: . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
1349: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

1351:   Output Parameter:
1352: . dm - The `DM` object

1354:   Level: beginner

1356:   Note:
1357:   To customize this mesh using options, use
1358: .vb
1359:   DMCreate(comm, &dm);
1360:   DMSetType(dm, DMPLEX);
1361:   DMSetFromOptions(dm);
1362: .ve
1363:   and use the options in `DMSetFromOptions()`.

1365:   Here is the numbering returned for 2 faces in each direction for tensor cells\:
1366: .vb
1367:  10---17---11---18----12
1368:   |         |         |
1369:   |         |         |
1370:  20    2   22    3    24
1371:   |         |         |
1372:   |         |         |
1373:   7---15----8---16----9
1374:   |         |         |
1375:   |         |         |
1376:  19    0   21    1   23
1377:   |         |         |
1378:   |         |         |
1379:   4---13----5---14----6
1380: .ve
1381:   and for simplicial cells
1382: .vb
1383:  14----8---15----9----16
1384:   |\     5  |\      7 |
1385:   | \       | \       |
1386:  13   2    14    3    15
1387:   | 4   \   | 6   \   |
1388:   |       \ |       \ |
1389:  11----6---12----7----13
1390:   |\        |\        |
1391:   | \    1  | \     3 |
1392:  10   0    11    1    12
1393:   | 0   \   | 2   \   |
1394:   |       \ |       \ |
1395:   8----4----9----5----10
1396: .ve

1398: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
1399: @*/
1400: PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, DM *dm)
1401: {
1402:   PetscInt       fac[3] = {1, 1, 1};
1403:   PetscReal      low[3] = {0, 0, 0};
1404:   PetscReal      upp[3] = {1, 1, 1};
1405:   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};

1407:   PetscFunctionBegin;
1408:   PetscCall(DMCreate(comm, dm));
1409:   PetscCall(DMSetType(*dm, DMPLEX));
1410:   PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate));
1411:   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
1412:   PetscFunctionReturn(PETSC_SUCCESS);
1413: }

1415: static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1416: {
1417:   DM       bdm, vol;
1418:   PetscInt i;

1420:   PetscFunctionBegin;
1421:   // TODO Now we can support periodicity
1422:   for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported");
1423:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm));
1424:   PetscCall(DMSetType(bdm, DMPLEX));
1425:   PetscCall(DMSetDimension(bdm, 2));
1426:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0));
1427:   PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE));
1428:   PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, &vol));
1429:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0));
1430:   PetscCall(DMDestroy(&bdm));
1431:   PetscCall(DMPlexReplace_Internal(dm, &vol));
1432:   if (lower[2] != 0.0) {
1433:     Vec          v;
1434:     PetscScalar *x;
1435:     PetscInt     cDim, n;

1437:     PetscCall(DMGetCoordinatesLocal(dm, &v));
1438:     PetscCall(VecGetBlockSize(v, &cDim));
1439:     PetscCall(VecGetLocalSize(v, &n));
1440:     PetscCall(VecGetArray(v, &x));
1441:     x += cDim;
1442:     for (i = 0; i < n; i += cDim) x[i] += lower[2];
1443:     PetscCall(VecRestoreArray(v, &x));
1444:     PetscCall(DMSetCoordinatesLocal(dm, v));
1445:   }
1446:   PetscFunctionReturn(PETSC_SUCCESS);
1447: }

1449: /*@
1450:   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tessellating the (x,y) plane and extruding in the third direction using wedge cells.

1452:   Collective

1454:   Input Parameters:
1455: + comm        - The communicator for the `DM` object
1456: . faces       - Number of faces per dimension, or `NULL` for (1, 1, 1)
1457: . lower       - The lower left corner, or `NULL` for (0, 0, 0)
1458: . upper       - The upper right corner, or `NULL` for (1, 1, 1)
1459: . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
1460: . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1461: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

1463:   Output Parameter:
1464: . dm - The `DM` object

1466:   Level: beginner

1468: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
1469: @*/
1470: PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm)
1471: {
1472:   PetscInt       fac[3] = {1, 1, 1};
1473:   PetscReal      low[3] = {0, 0, 0};
1474:   PetscReal      upp[3] = {1, 1, 1};
1475:   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};

1477:   PetscFunctionBegin;
1478:   PetscCall(DMCreate(comm, dm));
1479:   PetscCall(DMSetType(*dm, DMPLEX));
1480:   PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt));
1481:   if (!interpolate) {
1482:     DM udm;

1484:     PetscCall(DMPlexUninterpolate(*dm, &udm));
1485:     PetscCall(DMPlexReplace_Internal(*dm, &udm));
1486:   }
1487:   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
1488:   PetscFunctionReturn(PETSC_SUCCESS);
1489: }

1491: /*
1492:   DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension.

1494:   Input Parameters:
1495: + len - The length of the tuple
1496: . max - The maximum for each dimension, so values are in [0, max)
1497: - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition

1499:   Output Parameter:
1500: . tup - A tuple of `len` integers whose entries are at most `max`

1502:   Level: developer

1504:   Note:
1505:   Ordering is lexicographic with lowest index as least significant in ordering.
1506:   e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}.

1508: .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal()
1509: */
1510: static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[])
1511: {
1512:   PetscInt i;

1514:   PetscFunctionBegin;
1515:   for (i = 0; i < len; ++i) {
1516:     if (tup[i] < max[i] - 1) {
1517:       break;
1518:     } else {
1519:       tup[i] = 0;
1520:     }
1521:   }
1522:   if (i == len) tup[i - 1] = max[i - 1];
1523:   else ++tup[i];
1524:   PetscFunctionReturn(PETSC_SUCCESS);
1525: }

1527: static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[])
1528: {
1529:   PetscInt i, idx = tup[len - 1];

1531:   for (i = len - 2; i >= 0; --i) {
1532:     idx *= max[i];
1533:     idx += tup[i];
1534:   }
1535:   return idx;
1536: }

1538: static PetscErrorCode DestroyExtent_Private(void *extent)
1539: {
1540:   return PetscFree(extent);
1541: }

1543: static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], const DMBoundaryType bd[])
1544: {
1545:   Vec          coordinates;
1546:   PetscSection coordSection;
1547:   DMLabel      cutLabel    = NULL;
1548:   PetscBool    cutMarker   = PETSC_FALSE;
1549:   PetscBool    periodic    = PETSC_FALSE;
1550:   PetscInt     numCells    = 1, c;
1551:   PetscInt     numVertices = 1, v;
1552:   PetscScalar *coords;
1553:   PetscInt    *vertices, *vert, *vtmp, *supp, cone[2];
1554:   PetscInt     d, e, cell = 0, coordSize;
1555:   PetscMPIInt  rank;

1557:   PetscFunctionBegin;
1558:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1559:   PetscCall(DMSetDimension(dm, dim));
1560:   PetscCall(PetscCalloc4(dim, &vertices, dim, &vert, dim, &vtmp, 2 * dim, &supp));
1561:   PetscCall(DMCreateLabel(dm, "marker"));
1562:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
1563:   for (d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE;
1564:   if (periodic && cutMarker) {
1565:     PetscCall(DMCreateLabel(dm, "periodic_cut"));
1566:     PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
1567:   }
1568:   for (d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Hypercubic mesh must be periodic now");
1569:   for (d = 0; d < dim; ++d) {
1570:     vertices[d] = edges[d];
1571:     numVertices *= vertices[d];
1572:   }
1573:   numCells = numVertices * dim;
1574:   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
1575:   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2));
1576:   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim));
1577:   /* TODO Loop over boundary and reset support sizes */
1578:   PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */
1579:   /* Build cell cones and vertex supports */
1580:   PetscCall(DMCreateLabel(dm, "celltype"));
1581:   while (vert[dim - 1] < vertices[dim - 1]) {
1582:     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells;
1583:     PetscInt       s      = 0;

1585:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex));
1586:     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]));
1587:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1588:     PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT));
1589:     for (d = 0; d < dim; ++d) {
1590:       for (e = 0; e < dim; ++e) vtmp[e] = vert[e];
1591:       vtmp[d] = (vert[d] + 1) % vertices[d];
1592:       cone[0] = vertex;
1593:       cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells;
1594:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Vertex %" PetscInt_FMT ":", cone[1]));
1595:       for (e = 0; e < dim; ++e) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vtmp[e]));
1596:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1597:       PetscCall(DMPlexSetCone(dm, cell, cone));
1598:       PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT));
1599:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1]));
1600:       ++cell;
1601:     }
1602:     for (d = 0; d < dim; ++d) {
1603:       for (e = 0; e < dim; ++e) vtmp[e] = vert[e];
1604:       vtmp[d]   = (vert[d] + vertices[d] - 1) % vertices[d];
1605:       supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d;
1606:       supp[s++] = (vertex - numCells) * dim + d;
1607:       PetscCall(DMPlexSetSupport(dm, vertex, supp));
1608:     }
1609:     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
1610:   }
1611:   PetscCall(DMPlexStratify(dm));
1612:   /* Build coordinates */
1613:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
1614:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
1615:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1616:   PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
1617:   for (v = numCells; v < numCells + numVertices; ++v) {
1618:     PetscCall(PetscSectionSetDof(coordSection, v, dim));
1619:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1620:   }
1621:   PetscCall(PetscSectionSetUp(coordSection));
1622:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1623:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1624:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1625:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1626:   PetscCall(VecSetBlockSize(coordinates, dim));
1627:   PetscCall(VecSetType(coordinates, VECSTANDARD));
1628:   PetscCall(VecGetArray(coordinates, &coords));
1629:   for (d = 0; d < dim; ++d) vert[d] = 0;
1630:   while (vert[dim - 1] < vertices[dim - 1]) {
1631:     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert);

1633:     for (d = 0; d < dim; ++d) coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / vertices[d]) * vert[d];
1634:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex));
1635:     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]));
1636:     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(coords[vertex * dim + d])));
1637:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1638:     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
1639:   }
1640:   PetscCall(VecRestoreArray(coordinates, &coords));
1641:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1642:   PetscCall(VecDestroy(&coordinates));
1643:   PetscCall(PetscFree4(vertices, vert, vtmp, supp));
1644:   //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper));
1645:   // Attach the extent
1646:   {
1647:     PetscContainer c;
1648:     PetscInt      *extent;

1650:     PetscCall(PetscMalloc1(dim, &extent));
1651:     for (PetscInt d = 0; d < dim; ++d) extent[d] = edges[d];
1652:     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
1653:     PetscCall(PetscContainerSetUserDestroy(c, DestroyExtent_Private));
1654:     PetscCall(PetscContainerSetPointer(c, extent));
1655:     PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c));
1656:     PetscCall(PetscContainerDestroy(&c));
1657:   }
1658:   PetscFunctionReturn(PETSC_SUCCESS);
1659: }

1661: /*@C
1662:   DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges.

1664:   Collective

1666:   Input Parameters:
1667: + comm  - The communicator for the DM object
1668: . dim   - The spatial dimension
1669: . edges - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1670: . lower - The lower left corner, or `NULL` for (0, 0, 0)
1671: - upper - The upper right corner, or `NULL` for (1, 1, 1)

1673:   Output Parameter:
1674: . dm - The DM object

1676:   Level: beginner

1678:   Note:
1679:   If you want to customize this mesh using options, you just need to
1680: .vb
1681:   DMCreate(comm, &dm);
1682:   DMSetType(dm, DMPLEX);
1683:   DMSetFromOptions(dm);
1684: .ve
1685:   and use the options on the `DMSetFromOptions()` page.

1687:   The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively,
1688: .vb
1689:  18--0-19--2-20--4-18
1690:   |     |     |     |
1691:  13    15    17    13
1692:   |     |     |     |
1693:  24-12-25-14-26-16-24
1694:   |     |     |     |
1695:   7     9    11     7
1696:   |     |     |     |
1697:  21--6-22--8-23-10-21
1698:   |     |     |     |
1699:   1     3     5     1
1700:   |     |     |     |
1701:  18--0-19--2-20--4-18
1702: .ve

1704: .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
1705: @*/
1706: PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], DM *dm)
1707: {
1708:   PetscInt       *edg;
1709:   PetscReal      *low, *upp;
1710:   DMBoundaryType *bdt;
1711:   PetscInt        d;

1713:   PetscFunctionBegin;
1714:   PetscCall(DMCreate(comm, dm));
1715:   PetscCall(DMSetType(*dm, DMPLEX));
1716:   PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt));
1717:   for (d = 0; d < dim; ++d) {
1718:     edg[d] = edges ? edges[d] : 1;
1719:     low[d] = lower ? lower[d] : 0.;
1720:     upp[d] = upper ? upper[d] : 1.;
1721:     bdt[d] = DM_BOUNDARY_PERIODIC;
1722:   }
1723:   PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, bdt));
1724:   PetscCall(PetscFree4(edg, low, upp, bdt));
1725:   PetscFunctionReturn(PETSC_SUCCESS);
1726: }

1728: /*@C
1729:   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database.

1731:   Logically Collective

1733:   Input Parameters:
1734: + dm     - the `DM` context
1735: - prefix - the prefix to prepend to all option names

1737:   Level: advanced

1739:   Note:
1740:   A hyphen (-) must NOT be given at the beginning of the prefix name.
1741:   The first character of all runtime options is AUTOMATICALLY the hyphen.

1743: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()`
1744: @*/
1745: PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
1746: {
1747:   DM_Plex *mesh = (DM_Plex *)dm->data;

1749:   PetscFunctionBegin;
1751:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
1752:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix));
1753:   PetscFunctionReturn(PETSC_SUCCESS);
1754: }

1756: /* Remap geometry to cylinder
1757:    TODO: This only works for a single refinement, then it is broken

1759:      Interior square: Linear interpolation is correct
1760:      The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
1761:      such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance

1763:        phi     = arctan(y/x)
1764:        d_close = sqrt(1/8 + 1/4 sin^2(phi))
1765:        d_far   = sqrt(1/2 + sin^2(phi))

1767:      so we remap them using

1769:        x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
1770:        y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)

1772:      If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
1773: */
1774: static void snapToCylinder(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1775: {
1776:   const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
1777:   const PetscReal ds2 = 0.5 * dis;

1779:   if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) {
1780:     f0[0] = u[0];
1781:     f0[1] = u[1];
1782:   } else {
1783:     PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;

1785:     x    = PetscRealPart(u[0]);
1786:     y    = PetscRealPart(u[1]);
1787:     phi  = PetscAtan2Real(y, x);
1788:     sinp = PetscSinReal(phi);
1789:     cosp = PetscCosReal(phi);
1790:     if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) {
1791:       dc = PetscAbsReal(ds2 / sinp);
1792:       df = PetscAbsReal(dis / sinp);
1793:       xc = ds2 * x / PetscAbsReal(y);
1794:       yc = ds2 * PetscSignReal(y);
1795:     } else {
1796:       dc = PetscAbsReal(ds2 / cosp);
1797:       df = PetscAbsReal(dis / cosp);
1798:       xc = ds2 * PetscSignReal(x);
1799:       yc = ds2 * y / PetscAbsReal(x);
1800:     }
1801:     f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc);
1802:     f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc);
1803:   }
1804:   f0[2] = u[2];
1805: }

1807: static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ)
1808: {
1809:   const PetscInt dim = 3;
1810:   PetscInt       numCells, numVertices;
1811:   PetscMPIInt    rank;

1813:   PetscFunctionBegin;
1814:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1815:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1816:   PetscCall(DMSetDimension(dm, dim));
1817:   /* Create topology */
1818:   {
1819:     PetscInt cone[8], c;

1821:     numCells    = rank == 0 ? 5 : 0;
1822:     numVertices = rank == 0 ? 16 : 0;
1823:     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1824:       numCells *= 3;
1825:       numVertices = rank == 0 ? 24 : 0;
1826:     }
1827:     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
1828:     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8));
1829:     PetscCall(DMSetUp(dm));
1830:     if (rank == 0) {
1831:       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1832:         cone[0] = 15;
1833:         cone[1] = 18;
1834:         cone[2] = 17;
1835:         cone[3] = 16;
1836:         cone[4] = 31;
1837:         cone[5] = 32;
1838:         cone[6] = 33;
1839:         cone[7] = 34;
1840:         PetscCall(DMPlexSetCone(dm, 0, cone));
1841:         cone[0] = 16;
1842:         cone[1] = 17;
1843:         cone[2] = 24;
1844:         cone[3] = 23;
1845:         cone[4] = 32;
1846:         cone[5] = 36;
1847:         cone[6] = 37;
1848:         cone[7] = 33; /* 22 25 26 21 */
1849:         PetscCall(DMPlexSetCone(dm, 1, cone));
1850:         cone[0] = 18;
1851:         cone[1] = 27;
1852:         cone[2] = 24;
1853:         cone[3] = 17;
1854:         cone[4] = 34;
1855:         cone[5] = 33;
1856:         cone[6] = 37;
1857:         cone[7] = 38;
1858:         PetscCall(DMPlexSetCone(dm, 2, cone));
1859:         cone[0] = 29;
1860:         cone[1] = 27;
1861:         cone[2] = 18;
1862:         cone[3] = 15;
1863:         cone[4] = 35;
1864:         cone[5] = 31;
1865:         cone[6] = 34;
1866:         cone[7] = 38;
1867:         PetscCall(DMPlexSetCone(dm, 3, cone));
1868:         cone[0] = 29;
1869:         cone[1] = 15;
1870:         cone[2] = 16;
1871:         cone[3] = 23;
1872:         cone[4] = 35;
1873:         cone[5] = 36;
1874:         cone[6] = 32;
1875:         cone[7] = 31;
1876:         PetscCall(DMPlexSetCone(dm, 4, cone));

1878:         cone[0] = 31;
1879:         cone[1] = 34;
1880:         cone[2] = 33;
1881:         cone[3] = 32;
1882:         cone[4] = 19;
1883:         cone[5] = 22;
1884:         cone[6] = 21;
1885:         cone[7] = 20;
1886:         PetscCall(DMPlexSetCone(dm, 5, cone));
1887:         cone[0] = 32;
1888:         cone[1] = 33;
1889:         cone[2] = 37;
1890:         cone[3] = 36;
1891:         cone[4] = 22;
1892:         cone[5] = 25;
1893:         cone[6] = 26;
1894:         cone[7] = 21;
1895:         PetscCall(DMPlexSetCone(dm, 6, cone));
1896:         cone[0] = 34;
1897:         cone[1] = 38;
1898:         cone[2] = 37;
1899:         cone[3] = 33;
1900:         cone[4] = 20;
1901:         cone[5] = 21;
1902:         cone[6] = 26;
1903:         cone[7] = 28;
1904:         PetscCall(DMPlexSetCone(dm, 7, cone));
1905:         cone[0] = 35;
1906:         cone[1] = 38;
1907:         cone[2] = 34;
1908:         cone[3] = 31;
1909:         cone[4] = 30;
1910:         cone[5] = 19;
1911:         cone[6] = 20;
1912:         cone[7] = 28;
1913:         PetscCall(DMPlexSetCone(dm, 8, cone));
1914:         cone[0] = 35;
1915:         cone[1] = 31;
1916:         cone[2] = 32;
1917:         cone[3] = 36;
1918:         cone[4] = 30;
1919:         cone[5] = 25;
1920:         cone[6] = 22;
1921:         cone[7] = 19;
1922:         PetscCall(DMPlexSetCone(dm, 9, cone));

1924:         cone[0] = 19;
1925:         cone[1] = 20;
1926:         cone[2] = 21;
1927:         cone[3] = 22;
1928:         cone[4] = 15;
1929:         cone[5] = 16;
1930:         cone[6] = 17;
1931:         cone[7] = 18;
1932:         PetscCall(DMPlexSetCone(dm, 10, cone));
1933:         cone[0] = 22;
1934:         cone[1] = 21;
1935:         cone[2] = 26;
1936:         cone[3] = 25;
1937:         cone[4] = 16;
1938:         cone[5] = 23;
1939:         cone[6] = 24;
1940:         cone[7] = 17;
1941:         PetscCall(DMPlexSetCone(dm, 11, cone));
1942:         cone[0] = 20;
1943:         cone[1] = 28;
1944:         cone[2] = 26;
1945:         cone[3] = 21;
1946:         cone[4] = 18;
1947:         cone[5] = 17;
1948:         cone[6] = 24;
1949:         cone[7] = 27;
1950:         PetscCall(DMPlexSetCone(dm, 12, cone));
1951:         cone[0] = 30;
1952:         cone[1] = 28;
1953:         cone[2] = 20;
1954:         cone[3] = 19;
1955:         cone[4] = 29;
1956:         cone[5] = 15;
1957:         cone[6] = 18;
1958:         cone[7] = 27;
1959:         PetscCall(DMPlexSetCone(dm, 13, cone));
1960:         cone[0] = 30;
1961:         cone[1] = 19;
1962:         cone[2] = 22;
1963:         cone[3] = 25;
1964:         cone[4] = 29;
1965:         cone[5] = 23;
1966:         cone[6] = 16;
1967:         cone[7] = 15;
1968:         PetscCall(DMPlexSetCone(dm, 14, cone));
1969:       } else {
1970:         cone[0] = 5;
1971:         cone[1] = 8;
1972:         cone[2] = 7;
1973:         cone[3] = 6;
1974:         cone[4] = 9;
1975:         cone[5] = 12;
1976:         cone[6] = 11;
1977:         cone[7] = 10;
1978:         PetscCall(DMPlexSetCone(dm, 0, cone));
1979:         cone[0] = 6;
1980:         cone[1] = 7;
1981:         cone[2] = 14;
1982:         cone[3] = 13;
1983:         cone[4] = 12;
1984:         cone[5] = 15;
1985:         cone[6] = 16;
1986:         cone[7] = 11;
1987:         PetscCall(DMPlexSetCone(dm, 1, cone));
1988:         cone[0] = 8;
1989:         cone[1] = 17;
1990:         cone[2] = 14;
1991:         cone[3] = 7;
1992:         cone[4] = 10;
1993:         cone[5] = 11;
1994:         cone[6] = 16;
1995:         cone[7] = 18;
1996:         PetscCall(DMPlexSetCone(dm, 2, cone));
1997:         cone[0] = 19;
1998:         cone[1] = 17;
1999:         cone[2] = 8;
2000:         cone[3] = 5;
2001:         cone[4] = 20;
2002:         cone[5] = 9;
2003:         cone[6] = 10;
2004:         cone[7] = 18;
2005:         PetscCall(DMPlexSetCone(dm, 3, cone));
2006:         cone[0] = 19;
2007:         cone[1] = 5;
2008:         cone[2] = 6;
2009:         cone[3] = 13;
2010:         cone[4] = 20;
2011:         cone[5] = 15;
2012:         cone[6] = 12;
2013:         cone[7] = 9;
2014:         PetscCall(DMPlexSetCone(dm, 4, cone));
2015:       }
2016:     }
2017:     PetscCall(DMPlexSymmetrize(dm));
2018:     PetscCall(DMPlexStratify(dm));
2019:   }
2020:   /* Create cube geometry */
2021:   {
2022:     Vec             coordinates;
2023:     PetscSection    coordSection;
2024:     PetscScalar    *coords;
2025:     PetscInt        coordSize, v;
2026:     const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
2027:     const PetscReal ds2 = dis / 2.0;

2029:     /* Build coordinates */
2030:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2031:     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2032:     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2033:     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2034:     for (v = numCells; v < numCells + numVertices; ++v) {
2035:       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2036:       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2037:     }
2038:     PetscCall(PetscSectionSetUp(coordSection));
2039:     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2040:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2041:     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2042:     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2043:     PetscCall(VecSetBlockSize(coordinates, dim));
2044:     PetscCall(VecSetType(coordinates, VECSTANDARD));
2045:     PetscCall(VecGetArray(coordinates, &coords));
2046:     if (rank == 0) {
2047:       coords[0 * dim + 0]  = -ds2;
2048:       coords[0 * dim + 1]  = -ds2;
2049:       coords[0 * dim + 2]  = 0.0;
2050:       coords[1 * dim + 0]  = ds2;
2051:       coords[1 * dim + 1]  = -ds2;
2052:       coords[1 * dim + 2]  = 0.0;
2053:       coords[2 * dim + 0]  = ds2;
2054:       coords[2 * dim + 1]  = ds2;
2055:       coords[2 * dim + 2]  = 0.0;
2056:       coords[3 * dim + 0]  = -ds2;
2057:       coords[3 * dim + 1]  = ds2;
2058:       coords[3 * dim + 2]  = 0.0;
2059:       coords[4 * dim + 0]  = -ds2;
2060:       coords[4 * dim + 1]  = -ds2;
2061:       coords[4 * dim + 2]  = 1.0;
2062:       coords[5 * dim + 0]  = -ds2;
2063:       coords[5 * dim + 1]  = ds2;
2064:       coords[5 * dim + 2]  = 1.0;
2065:       coords[6 * dim + 0]  = ds2;
2066:       coords[6 * dim + 1]  = ds2;
2067:       coords[6 * dim + 2]  = 1.0;
2068:       coords[7 * dim + 0]  = ds2;
2069:       coords[7 * dim + 1]  = -ds2;
2070:       coords[7 * dim + 2]  = 1.0;
2071:       coords[8 * dim + 0]  = dis;
2072:       coords[8 * dim + 1]  = -dis;
2073:       coords[8 * dim + 2]  = 0.0;
2074:       coords[9 * dim + 0]  = dis;
2075:       coords[9 * dim + 1]  = dis;
2076:       coords[9 * dim + 2]  = 0.0;
2077:       coords[10 * dim + 0] = dis;
2078:       coords[10 * dim + 1] = -dis;
2079:       coords[10 * dim + 2] = 1.0;
2080:       coords[11 * dim + 0] = dis;
2081:       coords[11 * dim + 1] = dis;
2082:       coords[11 * dim + 2] = 1.0;
2083:       coords[12 * dim + 0] = -dis;
2084:       coords[12 * dim + 1] = dis;
2085:       coords[12 * dim + 2] = 0.0;
2086:       coords[13 * dim + 0] = -dis;
2087:       coords[13 * dim + 1] = dis;
2088:       coords[13 * dim + 2] = 1.0;
2089:       coords[14 * dim + 0] = -dis;
2090:       coords[14 * dim + 1] = -dis;
2091:       coords[14 * dim + 2] = 0.0;
2092:       coords[15 * dim + 0] = -dis;
2093:       coords[15 * dim + 1] = -dis;
2094:       coords[15 * dim + 2] = 1.0;
2095:       if (periodicZ == DM_BOUNDARY_PERIODIC) {
2096:         /* 15 31 19 */ coords[16 * dim + 0] = -ds2;
2097:         coords[16 * dim + 1]                = -ds2;
2098:         coords[16 * dim + 2]                = 0.5;
2099:         /* 16 32 22 */ coords[17 * dim + 0] = ds2;
2100:         coords[17 * dim + 1]                = -ds2;
2101:         coords[17 * dim + 2]                = 0.5;
2102:         /* 17 33 21 */ coords[18 * dim + 0] = ds2;
2103:         coords[18 * dim + 1]                = ds2;
2104:         coords[18 * dim + 2]                = 0.5;
2105:         /* 18 34 20 */ coords[19 * dim + 0] = -ds2;
2106:         coords[19 * dim + 1]                = ds2;
2107:         coords[19 * dim + 2]                = 0.5;
2108:         /* 29 35 30 */ coords[20 * dim + 0] = -dis;
2109:         coords[20 * dim + 1]                = -dis;
2110:         coords[20 * dim + 2]                = 0.5;
2111:         /* 23 36 25 */ coords[21 * dim + 0] = dis;
2112:         coords[21 * dim + 1]                = -dis;
2113:         coords[21 * dim + 2]                = 0.5;
2114:         /* 24 37 26 */ coords[22 * dim + 0] = dis;
2115:         coords[22 * dim + 1]                = dis;
2116:         coords[22 * dim + 2]                = 0.5;
2117:         /* 27 38 28 */ coords[23 * dim + 0] = -dis;
2118:         coords[23 * dim + 1]                = dis;
2119:         coords[23 * dim + 2]                = 0.5;
2120:       }
2121:     }
2122:     PetscCall(VecRestoreArray(coordinates, &coords));
2123:     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2124:     PetscCall(VecDestroy(&coordinates));
2125:   }
2126:   /* Create periodicity */
2127:   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
2128:     PetscReal L[3]       = {-1., -1., 0.};
2129:     PetscReal maxCell[3] = {-1., -1., 0.};
2130:     PetscReal lower[3]   = {0.0, 0.0, 0.0};
2131:     PetscReal upper[3]   = {1.0, 1.0, 1.5};
2132:     PetscInt  numZCells  = 3;

2134:     L[2]       = upper[2] - lower[2];
2135:     maxCell[2] = 1.1 * (L[2] / numZCells);
2136:     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
2137:   }
2138:   {
2139:     DM          cdm;
2140:     PetscDS     cds;
2141:     PetscScalar c[2] = {1.0, 1.0};

2143:     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToCylinder));
2144:     PetscCall(DMGetCoordinateDM(dm, &cdm));
2145:     PetscCall(DMGetDS(cdm, &cds));
2146:     PetscCall(PetscDSSetConstants(cds, 2, c));
2147:   }
2148:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));

2150:   /* Wait for coordinate creation before doing in-place modification */
2151:   PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2152:   PetscFunctionReturn(PETSC_SUCCESS);
2153: }

2155: /*@
2156:   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.

2158:   Collective

2160:   Input Parameters:
2161: + comm      - The communicator for the `DM` object
2162: - periodicZ - The boundary type for the Z direction

2164:   Output Parameter:
2165: . dm - The `DM` object

2167:   Level: beginner

2169:   Note:
2170:   Here is the output numbering looking from the bottom of the cylinder\:
2171: .vb
2172:        17-----14
2173:         |     |
2174:         |  2  |
2175:         |     |
2176:  17-----8-----7-----14
2177:   |     |     |     |
2178:   |  3  |  0  |  1  |
2179:   |     |     |     |
2180:  19-----5-----6-----13
2181:         |     |
2182:         |  4  |
2183:         |     |
2184:        19-----13

2186:  and up through the top

2188:        18-----16
2189:         |     |
2190:         |  2  |
2191:         |     |
2192:  18----10----11-----16
2193:   |     |     |     |
2194:   |  3  |  0  |  1  |
2195:   |     |     |     |
2196:  20-----9----12-----15
2197:         |     |
2198:         |  4  |
2199:         |     |
2200:        20-----15
2201: .ve

2203: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2204: @*/
2205: PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, DM *dm)
2206: {
2207:   PetscFunctionBegin;
2208:   PetscAssertPointer(dm, 3);
2209:   PetscCall(DMCreate(comm, dm));
2210:   PetscCall(DMSetType(*dm, DMPLEX));
2211:   PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ));
2212:   PetscFunctionReturn(PETSC_SUCCESS);
2213: }

2215: static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate)
2216: {
2217:   const PetscInt dim = 3;
2218:   PetscInt       numCells, numVertices, v;
2219:   PetscMPIInt    rank;

2221:   PetscFunctionBegin;
2222:   PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n);
2223:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2224:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2225:   PetscCall(DMSetDimension(dm, dim));
2226:   /* Must create the celltype label here so that we do not automatically try to compute the types */
2227:   PetscCall(DMCreateLabel(dm, "celltype"));
2228:   /* Create topology */
2229:   {
2230:     PetscInt cone[6], c;

2232:     numCells    = rank == 0 ? n : 0;
2233:     numVertices = rank == 0 ? 2 * (n + 1) : 0;
2234:     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
2235:     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
2236:     PetscCall(DMSetUp(dm));
2237:     for (c = 0; c < numCells; c++) {
2238:       cone[0] = c + n * 1;
2239:       cone[1] = (c + 1) % n + n * 1;
2240:       cone[2] = 0 + 3 * n;
2241:       cone[3] = c + n * 2;
2242:       cone[4] = (c + 1) % n + n * 2;
2243:       cone[5] = 1 + 3 * n;
2244:       PetscCall(DMPlexSetCone(dm, c, cone));
2245:       PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR));
2246:     }
2247:     PetscCall(DMPlexSymmetrize(dm));
2248:     PetscCall(DMPlexStratify(dm));
2249:   }
2250:   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT));
2251:   /* Create cylinder geometry */
2252:   {
2253:     Vec          coordinates;
2254:     PetscSection coordSection;
2255:     PetscScalar *coords;
2256:     PetscInt     coordSize, c;

2258:     /* Build coordinates */
2259:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2260:     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2261:     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2262:     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2263:     for (v = numCells; v < numCells + numVertices; ++v) {
2264:       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2265:       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2266:     }
2267:     PetscCall(PetscSectionSetUp(coordSection));
2268:     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2269:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2270:     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2271:     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2272:     PetscCall(VecSetBlockSize(coordinates, dim));
2273:     PetscCall(VecSetType(coordinates, VECSTANDARD));
2274:     PetscCall(VecGetArray(coordinates, &coords));
2275:     for (c = 0; c < numCells; c++) {
2276:       coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
2277:       coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
2278:       coords[(c + 0 * n) * dim + 2] = 1.0;
2279:       coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
2280:       coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
2281:       coords[(c + 1 * n) * dim + 2] = 0.0;
2282:     }
2283:     if (rank == 0) {
2284:       coords[(2 * n + 0) * dim + 0] = 0.0;
2285:       coords[(2 * n + 0) * dim + 1] = 0.0;
2286:       coords[(2 * n + 0) * dim + 2] = 1.0;
2287:       coords[(2 * n + 1) * dim + 0] = 0.0;
2288:       coords[(2 * n + 1) * dim + 1] = 0.0;
2289:       coords[(2 * n + 1) * dim + 2] = 0.0;
2290:     }
2291:     PetscCall(VecRestoreArray(coordinates, &coords));
2292:     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2293:     PetscCall(VecDestroy(&coordinates));
2294:   }
2295:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2296:   /* Interpolate */
2297:   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2298:   PetscFunctionReturn(PETSC_SUCCESS);
2299: }

2301: /*@
2302:   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.

2304:   Collective

2306:   Input Parameters:
2307: + comm        - The communicator for the `DM` object
2308: . n           - The number of wedges around the origin
2309: - interpolate - Create edges and faces

2311:   Output Parameter:
2312: . dm - The `DM` object

2314:   Level: beginner

2316: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2317: @*/
2318: PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
2319: {
2320:   PetscFunctionBegin;
2321:   PetscAssertPointer(dm, 4);
2322:   PetscCall(DMCreate(comm, dm));
2323:   PetscCall(DMSetType(*dm, DMPLEX));
2324:   PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate));
2325:   PetscFunctionReturn(PETSC_SUCCESS);
2326: }

2328: static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
2329: {
2330:   PetscReal prod = 0.0;
2331:   PetscInt  i;
2332:   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
2333:   return PetscSqrtReal(prod);
2334: }

2336: static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
2337: {
2338:   PetscReal prod = 0.0;
2339:   PetscInt  i;
2340:   for (i = 0; i < dim; ++i) prod += x[i] * y[i];
2341:   return prod;
2342: }

2344: /* The first constant is the sphere radius */
2345: static void snapToSphere(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
2346: {
2347:   PetscReal r     = PetscRealPart(constants[0]);
2348:   PetscReal norm2 = 0.0, fac;
2349:   PetscInt  n     = uOff[1] - uOff[0], d;

2351:   for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d]));
2352:   fac = r / PetscSqrtReal(norm2);
2353:   for (d = 0; d < n; ++d) f0[d] = u[d] * fac;
2354: }

2356: static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R)
2357: {
2358:   const PetscInt embedDim = dim + 1;
2359:   PetscSection   coordSection;
2360:   Vec            coordinates;
2361:   PetscScalar   *coords;
2362:   PetscReal     *coordsIn;
2363:   PetscInt       numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e;
2364:   PetscMPIInt    rank;

2366:   PetscFunctionBegin;
2368:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2369:   PetscCall(DMSetDimension(dm, dim));
2370:   PetscCall(DMSetCoordinateDim(dm, dim + 1));
2371:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2372:   switch (dim) {
2373:   case 1:
2374:     numCells = 16;
2375:     numVerts = numCells;

2377:     // Build Topology
2378:     PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2379:     for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2380:     PetscCall(DMSetUp(dm));
2381:     for (PetscInt c = 0; c < numCells; ++c) {
2382:       PetscInt cone[2];

2384:       cone[0] = c + numCells;
2385:       cone[1] = (c + 1) % numVerts + numCells;
2386:       PetscCall(DMPlexSetCone(dm, c, cone));
2387:     }
2388:     PetscCall(DMPlexSymmetrize(dm));
2389:     PetscCall(DMPlexStratify(dm));
2390:     PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn));
2391:     for (PetscInt v = 0; v < numVerts; ++v) {
2392:       const PetscReal rad = 2. * PETSC_PI * v / numVerts;

2394:       coordsIn[v * embedDim + 0] = PetscCosReal(rad);
2395:       coordsIn[v * embedDim + 1] = PetscSinReal(rad);
2396:     }
2397:     break;
2398:   case 2:
2399:     if (simplex) {
2400:       const PetscReal radius    = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI);
2401:       const PetscReal edgeLen   = 2.0 / (1.0 + PETSC_PHI) * (R / radius);
2402:       const PetscInt  degree    = 5;
2403:       PetscReal       vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)};
2404:       PetscInt        s[3]      = {1, 1, 1};
2405:       PetscInt        cone[3];
2406:       PetscInt       *graph;

2408:       vertex[0] *= R / radius;
2409:       vertex[1] *= R / radius;
2410:       vertex[2] *= R / radius;
2411:       numCells    = rank == 0 ? 20 : 0;
2412:       numVerts    = rank == 0 ? 12 : 0;
2413:       firstVertex = numCells;
2414:       /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of

2416:            (0, \pm 1/\phi+1, \pm \phi/\phi+1)

2418:          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2419:          length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393.
2420:       */
2421:       /* Construct vertices */
2422:       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2423:       if (rank == 0) {
2424:         for (PetscInt p = 0, i = 0; p < embedDim; ++p) {
2425:           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2426:             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2427:               for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim];
2428:               ++i;
2429:             }
2430:           }
2431:         }
2432:       }
2433:       /* Construct graph */
2434:       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
2435:       for (PetscInt i = 0; i < numVerts; ++i) {
2436:         PetscInt k = 0;
2437:         for (PetscInt j = 0; j < numVerts; ++j) {
2438:           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
2439:             graph[i * numVerts + j] = 1;
2440:             ++k;
2441:           }
2442:         }
2443:         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
2444:       }
2445:       /* Build Topology */
2446:       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2447:       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2448:       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2449:       /* Cells */
2450:       for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
2451:         for (PetscInt j = 0; j < i; ++j) {
2452:           for (PetscInt k = 0; k < j; ++k) {
2453:             if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) {
2454:               cone[0] = firstVertex + i;
2455:               cone[1] = firstVertex + j;
2456:               cone[2] = firstVertex + k;
2457:               /* Check orientation */
2458:               {
2459:                 const PetscInt epsilon[3][3][3] = {
2460:                   {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
2461:                   {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
2462:                   {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
2463:                 };
2464:                 PetscReal normal[3];
2465:                 PetscInt  e, f;

2467:                 for (d = 0; d < embedDim; ++d) {
2468:                   normal[d] = 0.0;
2469:                   for (e = 0; e < embedDim; ++e) {
2470:                     for (f = 0; f < embedDim; ++f) normal[d] += epsilon[d][e][f] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]);
2471:                   }
2472:                 }
2473:                 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
2474:                   PetscInt tmp = cone[1];
2475:                   cone[1]      = cone[2];
2476:                   cone[2]      = tmp;
2477:                 }
2478:               }
2479:               PetscCall(DMPlexSetCone(dm, c++, cone));
2480:             }
2481:           }
2482:         }
2483:       }
2484:       PetscCall(DMPlexSymmetrize(dm));
2485:       PetscCall(DMPlexStratify(dm));
2486:       PetscCall(PetscFree(graph));
2487:     } else {
2488:       /*
2489:         12-21--13
2490:          |     |
2491:         25  4  24
2492:          |     |
2493:   12-25--9-16--8-24--13
2494:    |     |     |     |
2495:   23  5 17  0 15  3  22
2496:    |     |     |     |
2497:   10-20--6-14--7-19--11
2498:          |     |
2499:         20  1  19
2500:          |     |
2501:         10-18--11
2502:          |     |
2503:         23  2  22
2504:          |     |
2505:         12-21--13
2506:        */
2507:       PetscInt cone[4], ornt[4];

2509:       numCells    = rank == 0 ? 6 : 0;
2510:       numEdges    = rank == 0 ? 12 : 0;
2511:       numVerts    = rank == 0 ? 8 : 0;
2512:       firstVertex = numCells;
2513:       firstEdge   = numCells + numVerts;
2514:       /* Build Topology */
2515:       PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts));
2516:       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4));
2517:       for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
2518:       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2519:       if (rank == 0) {
2520:         /* Cell 0 */
2521:         cone[0] = 14;
2522:         cone[1] = 15;
2523:         cone[2] = 16;
2524:         cone[3] = 17;
2525:         PetscCall(DMPlexSetCone(dm, 0, cone));
2526:         ornt[0] = 0;
2527:         ornt[1] = 0;
2528:         ornt[2] = 0;
2529:         ornt[3] = 0;
2530:         PetscCall(DMPlexSetConeOrientation(dm, 0, ornt));
2531:         /* Cell 1 */
2532:         cone[0] = 18;
2533:         cone[1] = 19;
2534:         cone[2] = 14;
2535:         cone[3] = 20;
2536:         PetscCall(DMPlexSetCone(dm, 1, cone));
2537:         ornt[0] = 0;
2538:         ornt[1] = 0;
2539:         ornt[2] = -1;
2540:         ornt[3] = 0;
2541:         PetscCall(DMPlexSetConeOrientation(dm, 1, ornt));
2542:         /* Cell 2 */
2543:         cone[0] = 21;
2544:         cone[1] = 22;
2545:         cone[2] = 18;
2546:         cone[3] = 23;
2547:         PetscCall(DMPlexSetCone(dm, 2, cone));
2548:         ornt[0] = 0;
2549:         ornt[1] = 0;
2550:         ornt[2] = -1;
2551:         ornt[3] = 0;
2552:         PetscCall(DMPlexSetConeOrientation(dm, 2, ornt));
2553:         /* Cell 3 */
2554:         cone[0] = 19;
2555:         cone[1] = 22;
2556:         cone[2] = 24;
2557:         cone[3] = 15;
2558:         PetscCall(DMPlexSetCone(dm, 3, cone));
2559:         ornt[0] = -1;
2560:         ornt[1] = -1;
2561:         ornt[2] = 0;
2562:         ornt[3] = -1;
2563:         PetscCall(DMPlexSetConeOrientation(dm, 3, ornt));
2564:         /* Cell 4 */
2565:         cone[0] = 16;
2566:         cone[1] = 24;
2567:         cone[2] = 21;
2568:         cone[3] = 25;
2569:         PetscCall(DMPlexSetCone(dm, 4, cone));
2570:         ornt[0] = -1;
2571:         ornt[1] = -1;
2572:         ornt[2] = -1;
2573:         ornt[3] = 0;
2574:         PetscCall(DMPlexSetConeOrientation(dm, 4, ornt));
2575:         /* Cell 5 */
2576:         cone[0] = 20;
2577:         cone[1] = 17;
2578:         cone[2] = 25;
2579:         cone[3] = 23;
2580:         PetscCall(DMPlexSetCone(dm, 5, cone));
2581:         ornt[0] = -1;
2582:         ornt[1] = -1;
2583:         ornt[2] = -1;
2584:         ornt[3] = -1;
2585:         PetscCall(DMPlexSetConeOrientation(dm, 5, ornt));
2586:         /* Edges */
2587:         cone[0] = 6;
2588:         cone[1] = 7;
2589:         PetscCall(DMPlexSetCone(dm, 14, cone));
2590:         cone[0] = 7;
2591:         cone[1] = 8;
2592:         PetscCall(DMPlexSetCone(dm, 15, cone));
2593:         cone[0] = 8;
2594:         cone[1] = 9;
2595:         PetscCall(DMPlexSetCone(dm, 16, cone));
2596:         cone[0] = 9;
2597:         cone[1] = 6;
2598:         PetscCall(DMPlexSetCone(dm, 17, cone));
2599:         cone[0] = 10;
2600:         cone[1] = 11;
2601:         PetscCall(DMPlexSetCone(dm, 18, cone));
2602:         cone[0] = 11;
2603:         cone[1] = 7;
2604:         PetscCall(DMPlexSetCone(dm, 19, cone));
2605:         cone[0] = 6;
2606:         cone[1] = 10;
2607:         PetscCall(DMPlexSetCone(dm, 20, cone));
2608:         cone[0] = 12;
2609:         cone[1] = 13;
2610:         PetscCall(DMPlexSetCone(dm, 21, cone));
2611:         cone[0] = 13;
2612:         cone[1] = 11;
2613:         PetscCall(DMPlexSetCone(dm, 22, cone));
2614:         cone[0] = 10;
2615:         cone[1] = 12;
2616:         PetscCall(DMPlexSetCone(dm, 23, cone));
2617:         cone[0] = 13;
2618:         cone[1] = 8;
2619:         PetscCall(DMPlexSetCone(dm, 24, cone));
2620:         cone[0] = 12;
2621:         cone[1] = 9;
2622:         PetscCall(DMPlexSetCone(dm, 25, cone));
2623:       }
2624:       PetscCall(DMPlexSymmetrize(dm));
2625:       PetscCall(DMPlexStratify(dm));
2626:       /* Build coordinates */
2627:       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2628:       if (rank == 0) {
2629:         coordsIn[0 * embedDim + 0] = -R;
2630:         coordsIn[0 * embedDim + 1] = R;
2631:         coordsIn[0 * embedDim + 2] = -R;
2632:         coordsIn[1 * embedDim + 0] = R;
2633:         coordsIn[1 * embedDim + 1] = R;
2634:         coordsIn[1 * embedDim + 2] = -R;
2635:         coordsIn[2 * embedDim + 0] = R;
2636:         coordsIn[2 * embedDim + 1] = -R;
2637:         coordsIn[2 * embedDim + 2] = -R;
2638:         coordsIn[3 * embedDim + 0] = -R;
2639:         coordsIn[3 * embedDim + 1] = -R;
2640:         coordsIn[3 * embedDim + 2] = -R;
2641:         coordsIn[4 * embedDim + 0] = -R;
2642:         coordsIn[4 * embedDim + 1] = R;
2643:         coordsIn[4 * embedDim + 2] = R;
2644:         coordsIn[5 * embedDim + 0] = R;
2645:         coordsIn[5 * embedDim + 1] = R;
2646:         coordsIn[5 * embedDim + 2] = R;
2647:         coordsIn[6 * embedDim + 0] = -R;
2648:         coordsIn[6 * embedDim + 1] = -R;
2649:         coordsIn[6 * embedDim + 2] = R;
2650:         coordsIn[7 * embedDim + 0] = R;
2651:         coordsIn[7 * embedDim + 1] = -R;
2652:         coordsIn[7 * embedDim + 2] = R;
2653:       }
2654:     }
2655:     break;
2656:   case 3:
2657:     if (simplex) {
2658:       const PetscReal edgeLen         = 1.0 / PETSC_PHI;
2659:       PetscReal       vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
2660:       PetscReal       vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
2661:       PetscReal       vertexC[4]      = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0};
2662:       const PetscInt  degree          = 12;
2663:       PetscInt        s[4]            = {1, 1, 1};
2664:       PetscInt        evenPerm[12][4] = {
2665:         {0, 1, 2, 3},
2666:         {0, 2, 3, 1},
2667:         {0, 3, 1, 2},
2668:         {1, 0, 3, 2},
2669:         {1, 2, 0, 3},
2670:         {1, 3, 2, 0},
2671:         {2, 0, 1, 3},
2672:         {2, 1, 3, 0},
2673:         {2, 3, 0, 1},
2674:         {3, 0, 2, 1},
2675:         {3, 1, 0, 2},
2676:         {3, 2, 1, 0}
2677:       };
2678:       PetscInt  cone[4];
2679:       PetscInt *graph, p, i, j, k, l;

2681:       vertexA[0] *= R;
2682:       vertexA[1] *= R;
2683:       vertexA[2] *= R;
2684:       vertexA[3] *= R;
2685:       vertexB[0] *= R;
2686:       vertexB[1] *= R;
2687:       vertexB[2] *= R;
2688:       vertexB[3] *= R;
2689:       vertexC[0] *= R;
2690:       vertexC[1] *= R;
2691:       vertexC[2] *= R;
2692:       vertexC[3] *= R;
2693:       numCells    = rank == 0 ? 600 : 0;
2694:       numVerts    = rank == 0 ? 120 : 0;
2695:       firstVertex = numCells;
2696:       /* Use the 600-cell, which for a unit sphere has coordinates which are

2698:            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
2699:                (\pm 1,    0,       0,      0)  all cyclic permutations   8
2700:            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96

2702:          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2703:          length is then given by 1/\phi = 0.61803.

2705:          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
2706:          http://mathworld.wolfram.com/600-Cell.html
2707:       */
2708:       /* Construct vertices */
2709:       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2710:       i = 0;
2711:       if (rank == 0) {
2712:         for (s[0] = -1; s[0] < 2; s[0] += 2) {
2713:           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2714:             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2715:               for (s[3] = -1; s[3] < 2; s[3] += 2) {
2716:                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d];
2717:                 ++i;
2718:               }
2719:             }
2720:           }
2721:         }
2722:         for (p = 0; p < embedDim; ++p) {
2723:           s[1] = s[2] = s[3] = 1;
2724:           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2725:             for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim];
2726:             ++i;
2727:           }
2728:         }
2729:         for (p = 0; p < 12; ++p) {
2730:           s[3] = 1;
2731:           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2732:             for (s[1] = -1; s[1] < 2; s[1] += 2) {
2733:               for (s[2] = -1; s[2] < 2; s[2] += 2) {
2734:                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]];
2735:                 ++i;
2736:               }
2737:             }
2738:           }
2739:         }
2740:       }
2741:       PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts);
2742:       /* Construct graph */
2743:       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
2744:       for (i = 0; i < numVerts; ++i) {
2745:         for (j = 0, k = 0; j < numVerts; ++j) {
2746:           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
2747:             graph[i * numVerts + j] = 1;
2748:             ++k;
2749:           }
2750:         }
2751:         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
2752:       }
2753:       /* Build Topology */
2754:       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2755:       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2756:       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2757:       /* Cells */
2758:       if (rank == 0) {
2759:         for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
2760:           for (j = 0; j < i; ++j) {
2761:             for (k = 0; k < j; ++k) {
2762:               for (l = 0; l < k; ++l) {
2763:                 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i] && graph[l * numVerts + i] && graph[l * numVerts + j] && graph[l * numVerts + k]) {
2764:                   cone[0] = firstVertex + i;
2765:                   cone[1] = firstVertex + j;
2766:                   cone[2] = firstVertex + k;
2767:                   cone[3] = firstVertex + l;
2768:                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
2769:                   {
2770:                     const PetscInt epsilon[4][4][4][4] = {
2771:                       {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, -1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 0, 0}, {0, 1, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 1, 0}, {0, -1, 0, 0}, {0, 0, 0, 0}}},

2773:                       {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 0, 0, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}}, {{0, 0, -1, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}}},

2775:                       {{{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}, {0, -1, 0, 0}}, {{0, 0, 0, -1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 1, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}},

2777:                       {{{0, 0, 0, 0}, {0, 0, -1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 1, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}}, {{0, -1, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} }
2778:                     };
2779:                     PetscReal normal[4];
2780:                     PetscInt  e, f, g;

2782:                     for (d = 0; d < embedDim; ++d) {
2783:                       normal[d] = 0.0;
2784:                       for (e = 0; e < embedDim; ++e) {
2785:                         for (f = 0; f < embedDim; ++f) {
2786:                           for (g = 0; g < embedDim; ++g) {
2787:                             normal[d] += epsilon[d][e][f][g] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]) * (coordsIn[l * embedDim + f] - coordsIn[i * embedDim + f]);
2788:                           }
2789:                         }
2790:                       }
2791:                     }
2792:                     if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
2793:                       PetscInt tmp = cone[1];
2794:                       cone[1]      = cone[2];
2795:                       cone[2]      = tmp;
2796:                     }
2797:                   }
2798:                   PetscCall(DMPlexSetCone(dm, c++, cone));
2799:                 }
2800:               }
2801:             }
2802:           }
2803:         }
2804:       }
2805:       PetscCall(DMPlexSymmetrize(dm));
2806:       PetscCall(DMPlexStratify(dm));
2807:       PetscCall(PetscFree(graph));
2808:     }
2809:     break;
2810:   default:
2811:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim);
2812:   }
2813:   /* Create coordinates */
2814:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2815:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
2816:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim));
2817:   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts));
2818:   for (v = firstVertex; v < firstVertex + numVerts; ++v) {
2819:     PetscCall(PetscSectionSetDof(coordSection, v, embedDim));
2820:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim));
2821:   }
2822:   PetscCall(PetscSectionSetUp(coordSection));
2823:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2824:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2825:   PetscCall(VecSetBlockSize(coordinates, embedDim));
2826:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2827:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2828:   PetscCall(VecSetType(coordinates, VECSTANDARD));
2829:   PetscCall(VecGetArray(coordinates, &coords));
2830:   for (v = 0; v < numVerts; ++v)
2831:     for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d];
2832:   PetscCall(VecRestoreArray(coordinates, &coords));
2833:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2834:   PetscCall(VecDestroy(&coordinates));
2835:   PetscCall(PetscFree(coordsIn));
2836:   {
2837:     DM          cdm;
2838:     PetscDS     cds;
2839:     PetscScalar c = R;

2841:     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToSphere));
2842:     PetscCall(DMGetCoordinateDM(dm, &cdm));
2843:     PetscCall(DMGetDS(cdm, &cds));
2844:     PetscCall(PetscDSSetConstants(cds, 1, &c));
2845:   }
2846:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2847:   /* Wait for coordinate creation before doing in-place modification */
2848:   if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2849:   PetscFunctionReturn(PETSC_SUCCESS);
2850: }

2852: typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]);

2854: /*
2855:  The Schwarz P implicit surface is

2857:      f(x) = cos(x0) + cos(x1) + cos(x2) = 0
2858: */
2859: static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
2860: {
2861:   PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)};
2862:   PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)};
2863:   f[0]           = c[0] + c[1] + c[2];
2864:   for (PetscInt i = 0; i < 3; i++) {
2865:     grad[i] = PETSC_PI * g[i];
2866:     for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.;
2867:   }
2868: }

2870: // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
2871: static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
2872: {
2873:   for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI);
2874:   return PETSC_SUCCESS;
2875: }

2877: /*
2878:  The Gyroid implicit surface is

2880:  f(x,y,z) = sin(pi * x) * cos (pi * (y + 1/2))  + sin(pi * (y + 1/2)) * cos(pi * (z + 1/4)) + sin(pi * (z + 1/4)) * cos(pi * x)

2882: */
2883: static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
2884: {
2885:   PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))};
2886:   PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))};
2887:   f[0]           = s[0] * c[1] + s[1] * c[2] + s[2] * c[0];
2888:   grad[0]        = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
2889:   grad[1]        = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
2890:   grad[2]        = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
2891:   hess[0][0]     = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]);
2892:   hess[0][1]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
2893:   hess[0][2]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
2894:   hess[1][0]     = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]);
2895:   hess[1][1]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
2896:   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
2897:   hess[2][0]     = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]);
2898:   hess[2][1]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
2899:   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
2900: }

2902: // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
2903: static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
2904: {
2905:   PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))};
2906:   PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))};
2907:   u[0]           = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
2908:   u[1]           = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
2909:   u[2]           = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
2910:   return PETSC_SUCCESS;
2911: }

2913: /*
2914:    We wish to solve

2916:          min_y || y - x ||^2  subject to f(y) = 0

2918:    Let g(y) = grad(f).  The minimization problem is equivalent to asking to satisfy
2919:    f(y) = 0 and (y-x) is parallel to g(y).  We do this by using Householder QR to obtain a basis for the
2920:    tangent space and ask for both components in the tangent space to be zero.

2922:    Take g to be a column vector and compute the "full QR" factorization Q R = g,
2923:    where Q = I - 2 n n^T is a symmetric orthogonal matrix.
2924:    The first column of Q is parallel to g so the remaining two columns span the null space.
2925:    Let Qn = Q[:,1:] be those remaining columns.  Then Qn Qn^T is an orthogonal projector into the tangent space.
2926:    Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries.
2927:    In total, we have a system of 3 equations in 3 unknowns:

2929:      f(y) = 0                       1 equation
2930:      Qn^T (y - x) = 0               2 equations

2932:    Here, we compute the residual and Jacobian of this system.
2933: */
2934: static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[])
2935: {
2936:   PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])};
2937:   PetscReal d[3]     = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])};
2938:   PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign;
2939:   PetscReal n_y[3][3] = {
2940:     {0, 0, 0},
2941:     {0, 0, 0},
2942:     {0, 0, 0}
2943:   };

2945:   feval(yreal, &f, grad, n_y);

2947:   for (PetscInt i = 0; i < 3; i++) n[i] = grad[i];
2948:   norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
2949:   for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i];

2951:   // Define the Householder reflector
2952:   sign = n[0] >= 0 ? 1. : -1.;
2953:   n[0] += norm * sign;
2954:   for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign;

2956:   norm      = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
2957:   norm_y[0] = 1. / norm * (n[0] * n_y[0][0]);
2958:   norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]);
2959:   norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]);

2961:   for (PetscInt i = 0; i < 3; i++) {
2962:     n[i] /= norm;
2963:     for (PetscInt j = 0; j < 3; j++) {
2964:       // note that n[i] is n_old[i]/norm when executing the code below
2965:       n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j];
2966:     }
2967:   }

2969:   nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2];
2970:   for (PetscInt i = 0; i < 3; i++) nd_y[i] = n[i] + n_y[0][i] * d[0] + n_y[1][i] * d[1] + n_y[2][i] * d[2];

2972:   res[0] = f;
2973:   res[1] = d[1] - 2 * n[1] * nd;
2974:   res[2] = d[2] - 2 * n[2] * nd;
2975:   // J[j][i] is J_{ij} (column major)
2976:   for (PetscInt j = 0; j < 3; j++) {
2977:     J[0 + j * 3] = grad[j];
2978:     J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]);
2979:     J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]);
2980:   }
2981: }

2983: /*
2984:    Project x to the nearest point on the implicit surface using Newton's method.
2985: */
2986: static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[])
2987: {
2988:   PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess

2990:   PetscFunctionBegin;
2991:   for (PetscInt iter = 0; iter < 10; iter++) {
2992:     PetscScalar res[3], J[9];
2993:     PetscReal   resnorm;
2994:     TPSNearestPointResJac(feval, x, y, res, J);
2995:     resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2])));
2996:     if (0) { // Turn on this monitor if you need to confirm quadratic convergence
2997:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%" PetscInt_FMT "] res [%g %g %g]\n", iter, (double)PetscRealPart(res[0]), (double)PetscRealPart(res[1]), (double)PetscRealPart(res[2])));
2998:     }
2999:     if (resnorm < PETSC_SMALL) break;

3001:     // Take the Newton step
3002:     PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL));
3003:     PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res);
3004:   }
3005:   for (PetscInt i = 0; i < 3; i++) x[i] = y[i];
3006:   PetscFunctionReturn(PETSC_SUCCESS);
3007: }

3009: const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL};

3011: static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness)
3012: {
3013:   PetscMPIInt rank;
3014:   PetscInt    topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0;
3015:   PetscInt(*edges)[2] = NULL, *edgeSets = NULL;
3016:   PetscInt           *cells_flat = NULL;
3017:   PetscReal          *vtxCoords  = NULL;
3018:   TPSEvaluateFunc     evalFunc   = NULL;
3019:   PetscSimplePointFn *normalFunc = NULL;
3020:   DMLabel             label;

3022:   PetscFunctionBegin;
3023:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
3024:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3025:   PetscCheck((layers != 0) ^ (thickness == 0.), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Layers %" PetscInt_FMT " must be nonzero iff thickness %g is nonzero", layers, (double)thickness);
3026:   switch (tpstype) {
3027:   case DMPLEX_TPS_SCHWARZ_P:
3028:     PetscCheck(!periodic || (periodic[0] == DM_BOUNDARY_NONE && periodic[1] == DM_BOUNDARY_NONE && periodic[2] == DM_BOUNDARY_NONE), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Schwarz P does not support periodic meshes");
3029:     if (rank == 0) {
3030:       PetscInt(*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn]
3031:       PetscInt  Njunctions = 0, Ncuts = 0, Npipes[3], vcount;
3032:       PetscReal L = 1;

3034:       Npipes[0]   = (extent[0] + 1) * extent[1] * extent[2];
3035:       Npipes[1]   = extent[0] * (extent[1] + 1) * extent[2];
3036:       Npipes[2]   = extent[0] * extent[1] * (extent[2] + 1);
3037:       Njunctions  = extent[0] * extent[1] * extent[2];
3038:       Ncuts       = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]);
3039:       numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions;
3040:       PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords));
3041:       PetscCall(PetscMalloc1(Njunctions, &cells));
3042:       PetscCall(PetscMalloc1(Ncuts * 4, &edges));
3043:       PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets));
3044:       // x-normal pipes
3045:       vcount = 0;
3046:       for (PetscInt i = 0; i < extent[0] + 1; i++) {
3047:         for (PetscInt j = 0; j < extent[1]; j++) {
3048:           for (PetscInt k = 0; k < extent[2]; k++) {
3049:             for (PetscInt l = 0; l < 4; l++) {
3050:               vtxCoords[vcount++] = (2 * i - 1) * L;
3051:               vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3052:               vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3053:             }
3054:           }
3055:         }
3056:       }
3057:       // y-normal pipes
3058:       for (PetscInt i = 0; i < extent[0]; i++) {
3059:         for (PetscInt j = 0; j < extent[1] + 1; j++) {
3060:           for (PetscInt k = 0; k < extent[2]; k++) {
3061:             for (PetscInt l = 0; l < 4; l++) {
3062:               vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3063:               vtxCoords[vcount++] = (2 * j - 1) * L;
3064:               vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3065:             }
3066:           }
3067:         }
3068:       }
3069:       // z-normal pipes
3070:       for (PetscInt i = 0; i < extent[0]; i++) {
3071:         for (PetscInt j = 0; j < extent[1]; j++) {
3072:           for (PetscInt k = 0; k < extent[2] + 1; k++) {
3073:             for (PetscInt l = 0; l < 4; l++) {
3074:               vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3075:               vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3076:               vtxCoords[vcount++] = (2 * k - 1) * L;
3077:             }
3078:           }
3079:         }
3080:       }
3081:       // junctions
3082:       for (PetscInt i = 0; i < extent[0]; i++) {
3083:         for (PetscInt j = 0; j < extent[1]; j++) {
3084:           for (PetscInt k = 0; k < extent[2]; k++) {
3085:             const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8;
3086:             PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count");
3087:             for (PetscInt ii = 0; ii < 2; ii++) {
3088:               for (PetscInt jj = 0; jj < 2; jj++) {
3089:                 for (PetscInt kk = 0; kk < 2; kk++) {
3090:                   double Ls           = (1 - sqrt(2) / 4) * L;
3091:                   vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls;
3092:                   vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls;
3093:                   vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls;
3094:                 }
3095:               }
3096:             }
3097:             const PetscInt jfaces[3][2][4] = {
3098:               {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned
3099:               {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned
3100:               {{6, 2, 0, 4}, {7, 3, 1, 5}}  // z-aligned
3101:             };
3102:             const PetscInt pipe_lo[3] = {// vertex numbers of pipes
3103:                                          ((i * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + Npipes[0] + Npipes[1]) * 4};
3104:             const PetscInt pipe_hi[3] = {// vertex numbers of pipes
3105:                                          (((i + 1) * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j + 1) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + 1 + Npipes[0] + Npipes[1]) * 4};
3106:             for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z
3107:               const PetscInt ijk[3] = {i, j, k};
3108:               for (PetscInt l = 0; l < 4; l++) { // rotations
3109:                 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l;
3110:                 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l];
3111:                 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4];
3112:                 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4;
3113:                 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l];
3114:                 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l;
3115:                 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4;
3116:                 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4];
3117:                 if (ijk[dir] == 0) {
3118:                   edges[numEdges][0] = pipe_lo[dir] + l;
3119:                   edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4;
3120:                   edgeSets[numEdges] = dir * 2 + 1;
3121:                   numEdges++;
3122:                 }
3123:                 if (ijk[dir] + 1 == extent[dir]) {
3124:                   edges[numEdges][0] = pipe_hi[dir] + l;
3125:                   edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4;
3126:                   edgeSets[numEdges] = dir * 2 + 2;
3127:                   numEdges++;
3128:                 }
3129:               }
3130:             }
3131:           }
3132:         }
3133:       }
3134:       PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts);
3135:       numFaces   = 24 * Njunctions;
3136:       cells_flat = cells[0][0][0];
3137:     }
3138:     evalFunc   = TPSEvaluate_SchwarzP;
3139:     normalFunc = TPSExtrudeNormalFunc_SchwarzP;
3140:     break;
3141:   case DMPLEX_TPS_GYROID:
3142:     if (rank == 0) {
3143:       // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set
3144:       //
3145:       //     sin(pi*x)*cos(pi*(y+1/2)) + sin(pi*(y+1/2))*cos(pi*(z+1/4)) + sin(pi*(z+1/4))*cos(x)
3146:       //
3147:       // on the cell [0,2]^3.
3148:       //
3149:       // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2].
3150:       // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins
3151:       // like a boomerang:
3152:       //
3153:       //     z = 0          z = 1/4        z = 1/2        z = 3/4     //
3154:       //     -----          -------        -------        -------     //
3155:       //                                                              //
3156:       //     +       +      +       +      +       +      +   \   +   //
3157:       //      \                                   /            \      //
3158:       //       \            `-_   _-'            /              }     //
3159:       //        *-_            `-'            _-'              /      //
3160:       //     +     `-+      +       +      +-'     +      +   /   +   //
3161:       //                                                              //
3162:       //                                                              //
3163:       //     z = 1          z = 5/4        z = 3/2        z = 7/4     //
3164:       //     -----          -------        -------        -------     //
3165:       //                                                              //
3166:       //     +-_     +      +       +      +     _-+      +   /   +   //
3167:       //        `-_            _-_            _-`            /        //
3168:       //           \        _-'   `-_        /              {         //
3169:       //            \                       /                \        //
3170:       //     +       +      +       +      +       +      +   \   +   //
3171:       //
3172:       //
3173:       // This course mesh approximates each of these slices by two line segments,
3174:       // and then connects the segments in consecutive layers with quadrilateral faces.
3175:       // All of the end points of the segments are multiples of 1/4 except for the
3176:       // point * in the picture for z = 0 above and the similar points in other layers.
3177:       // That point is at (gamma, gamma, 0), where gamma is calculated below.
3178:       //
3179:       // The column  [1,2]x[1,2]x[0,2] looks the same as this column;
3180:       // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images.
3181:       //
3182:       // As for how this method turned into the names given to the vertices:
3183:       // that was not systematic, it was just the way it worked out in my handwritten notes.

3185:       PetscInt facesPerBlock = 64;
3186:       PetscInt vertsPerBlock = 56;
3187:       PetscInt extentPlus[3];
3188:       PetscInt numBlocks, numBlocksPlus;
3189:       const PetscInt A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, II = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14, P = 15, Q = 16, R = 17, S = 18, T = 19, U = 20, V = 21, W = 22, X = 23, Y = 24, Z = 25, Ap = 26, Bp = 27, Cp = 28, Dp = 29, Ep = 30, Fp = 31, Gp = 32, Hp = 33, Ip = 34, Jp = 35, Kp = 36, Lp = 37, Mp = 38, Np = 39, Op = 40, Pp = 41, Qp = 42, Rp = 43, Sp = 44, Tp = 45, Up = 46, Vp = 47, Wp = 48, Xp = 49, Yp = 50, Zp = 51, Aq = 52, Bq = 53, Cq = 54, Dq = 55;
3190:       const PetscInt pattern[64][4] = {
3191:         /* face to vertex within the coarse discretization of a single gyroid block */
3192:         /* layer 0 */
3193:         {A,           C,           K,           G          },
3194:         {C,           B,           II,          K          },
3195:         {D,           A,           H,           L          },
3196:         {B + 56 * 1,  D,           L,           J          },
3197:         {E,           B + 56 * 1,  J,           N          },
3198:         {A + 56 * 2,  E,           N,           H + 56 * 2 },
3199:         {F,           A + 56 * 2,  G + 56 * 2,  M          },
3200:         {B,           F,           M,           II         },
3201:         /* layer 1 */
3202:         {G,           K,           Q,           O          },
3203:         {K,           II,          P,           Q          },
3204:         {L,           H,           O + 56 * 1,  R          },
3205:         {J,           L,           R,           P          },
3206:         {N,           J,           P,           S          },
3207:         {H + 56 * 2,  N,           S,           O + 56 * 3 },
3208:         {M,           G + 56 * 2,  O + 56 * 2,  T          },
3209:         {II,          M,           T,           P          },
3210:         /* layer 2 */
3211:         {O,           Q,           Y,           U          },
3212:         {Q,           P,           W,           Y          },
3213:         {R,           O + 56 * 1,  U + 56 * 1,  Ap         },
3214:         {P,           R,           Ap,          W          },
3215:         {S,           P,           X,           Bp         },
3216:         {O + 56 * 3,  S,           Bp,          V + 56 * 1 },
3217:         {T,           O + 56 * 2,  V,           Z          },
3218:         {P,           T,           Z,           X          },
3219:         /* layer 3 */
3220:         {U,           Y,           Ep,          Dp         },
3221:         {Y,           W,           Cp,          Ep         },
3222:         {Ap,          U + 56 * 1,  Dp + 56 * 1, Gp         },
3223:         {W,           Ap,          Gp,          Cp         },
3224:         {Bp,          X,           Cp + 56 * 2, Fp         },
3225:         {V + 56 * 1,  Bp,          Fp,          Dp + 56 * 1},
3226:         {Z,           V,           Dp,          Hp         },
3227:         {X,           Z,           Hp,          Cp + 56 * 2},
3228:         /* layer 4 */
3229:         {Dp,          Ep,          Mp,          Kp         },
3230:         {Ep,          Cp,          Ip,          Mp         },
3231:         {Gp,          Dp + 56 * 1, Lp,          Np         },
3232:         {Cp,          Gp,          Np,          Jp         },
3233:         {Fp,          Cp + 56 * 2, Jp + 56 * 2, Pp         },
3234:         {Dp + 56 * 1, Fp,          Pp,          Lp         },
3235:         {Hp,          Dp,          Kp,          Op         },
3236:         {Cp + 56 * 2, Hp,          Op,          Ip + 56 * 2},
3237:         /* layer 5 */
3238:         {Kp,          Mp,          Sp,          Rp         },
3239:         {Mp,          Ip,          Qp,          Sp         },
3240:         {Np,          Lp,          Rp,          Tp         },
3241:         {Jp,          Np,          Tp,          Qp + 56 * 1},
3242:         {Pp,          Jp + 56 * 2, Qp + 56 * 3, Up         },
3243:         {Lp,          Pp,          Up,          Rp         },
3244:         {Op,          Kp,          Rp,          Vp         },
3245:         {Ip + 56 * 2, Op,          Vp,          Qp + 56 * 2},
3246:         /* layer 6 */
3247:         {Rp,          Sp,          Aq,          Yp         },
3248:         {Sp,          Qp,          Wp,          Aq         },
3249:         {Tp,          Rp,          Yp,          Cq         },
3250:         {Qp + 56 * 1, Tp,          Cq,          Wp + 56 * 1},
3251:         {Up,          Qp + 56 * 3, Xp + 56 * 1, Dq         },
3252:         {Rp,          Up,          Dq,          Zp         },
3253:         {Vp,          Rp,          Zp,          Bq         },
3254:         {Qp + 56 * 2, Vp,          Bq,          Xp         },
3255:         /* layer 7 (the top is the periodic image of the bottom of layer 0) */
3256:         {Yp,          Aq,          C + 56 * 4,  A + 56 * 4 },
3257:         {Aq,          Wp,          B + 56 * 4,  C + 56 * 4 },
3258:         {Cq,          Yp,          A + 56 * 4,  D + 56 * 4 },
3259:         {Wp + 56 * 1, Cq,          D + 56 * 4,  B + 56 * 5 },
3260:         {Dq,          Xp + 56 * 1, B + 56 * 5,  E + 56 * 4 },
3261:         {Zp,          Dq,          E + 56 * 4,  A + 56 * 6 },
3262:         {Bq,          Zp,          A + 56 * 6,  F + 56 * 4 },
3263:         {Xp,          Bq,          F + 56 * 4,  B + 56 * 4 }
3264:       };
3265:       const PetscReal gamma                = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI;
3266:       const PetscReal patternCoords[56][3] = {
3267:         {1.,        0.,        0.  }, /* A  */
3268:         {0.,        1.,        0.  }, /* B  */
3269:         {gamma,     gamma,     0.  }, /* C  */
3270:         {1 + gamma, 1 - gamma, 0.  }, /* D  */
3271:         {2 - gamma, 2 - gamma, 0.  }, /* E  */
3272:         {1 - gamma, 1 + gamma, 0.  }, /* F  */

3274:         {.5,        0,         .25 }, /* G  */
3275:         {1.5,       0.,        .25 }, /* H  */
3276:         {.5,        1.,        .25 }, /* II */
3277:         {1.5,       1.,        .25 }, /* J  */
3278:         {.25,       .5,        .25 }, /* K  */
3279:         {1.25,      .5,        .25 }, /* L  */
3280:         {.75,       1.5,       .25 }, /* M  */
3281:         {1.75,      1.5,       .25 }, /* N  */

3283:         {0.,        0.,        .5  }, /* O  */
3284:         {1.,        1.,        .5  }, /* P  */
3285:         {gamma,     1 - gamma, .5  }, /* Q  */
3286:         {1 + gamma, gamma,     .5  }, /* R  */
3287:         {2 - gamma, 1 + gamma, .5  }, /* S  */
3288:         {1 - gamma, 2 - gamma, .5  }, /* T  */

3290:         {0.,        .5,        .75 }, /* U  */
3291:         {0.,        1.5,       .75 }, /* V  */
3292:         {1.,        .5,        .75 }, /* W  */
3293:         {1.,        1.5,       .75 }, /* X  */
3294:         {.5,        .75,       .75 }, /* Y  */
3295:         {.5,        1.75,      .75 }, /* Z  */
3296:         {1.5,       .25,       .75 }, /* Ap */
3297:         {1.5,       1.25,      .75 }, /* Bp */

3299:         {1.,        0.,        1.  }, /* Cp */
3300:         {0.,        1.,        1.  }, /* Dp */
3301:         {1 - gamma, 1 - gamma, 1.  }, /* Ep */
3302:         {1 + gamma, 1 + gamma, 1.  }, /* Fp */
3303:         {2 - gamma, gamma,     1.  }, /* Gp */
3304:         {gamma,     2 - gamma, 1.  }, /* Hp */

3306:         {.5,        0.,        1.25}, /* Ip */
3307:         {1.5,       0.,        1.25}, /* Jp */
3308:         {.5,        1.,        1.25}, /* Kp */
3309:         {1.5,       1.,        1.25}, /* Lp */
3310:         {.75,       .5,        1.25}, /* Mp */
3311:         {1.75,      .5,        1.25}, /* Np */
3312:         {.25,       1.5,       1.25}, /* Op */
3313:         {1.25,      1.5,       1.25}, /* Pp */

3315:         {0.,        0.,        1.5 }, /* Qp */
3316:         {1.,        1.,        1.5 }, /* Rp */
3317:         {1 - gamma, gamma,     1.5 }, /* Sp */
3318:         {2 - gamma, 1 - gamma, 1.5 }, /* Tp */
3319:         {1 + gamma, 2 - gamma, 1.5 }, /* Up */
3320:         {gamma,     1 + gamma, 1.5 }, /* Vp */

3322:         {0.,        .5,        1.75}, /* Wp */
3323:         {0.,        1.5,       1.75}, /* Xp */
3324:         {1.,        .5,        1.75}, /* Yp */
3325:         {1.,        1.5,       1.75}, /* Zp */
3326:         {.5,        .25,       1.75}, /* Aq */
3327:         {.5,        1.25,      1.75}, /* Bq */
3328:         {1.5,       .75,       1.75}, /* Cq */
3329:         {1.5,       1.75,      1.75}, /* Dq */
3330:       };
3331:       PetscInt(*cells)[64][4] = NULL;
3332:       PetscBool *seen;
3333:       PetscInt  *vertToTrueVert;
3334:       PetscInt   count;

3336:       for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1;
3337:       numBlocks = 1;
3338:       for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i];
3339:       numBlocksPlus = 1;
3340:       for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i];
3341:       numFaces = numBlocks * facesPerBlock;
3342:       PetscCall(PetscMalloc1(numBlocks, &cells));
3343:       PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen));
3344:       for (PetscInt k = 0; k < extent[2]; k++) {
3345:         for (PetscInt j = 0; j < extent[1]; j++) {
3346:           for (PetscInt i = 0; i < extent[0]; i++) {
3347:             for (PetscInt f = 0; f < facesPerBlock; f++) {
3348:               for (PetscInt v = 0; v < 4; v++) {
3349:                 PetscInt vertRaw     = pattern[f][v];
3350:                 PetscInt blockidx    = vertRaw / 56;
3351:                 PetscInt patternvert = vertRaw % 56;
3352:                 PetscInt xplus       = (blockidx & 1);
3353:                 PetscInt yplus       = (blockidx & 2) >> 1;
3354:                 PetscInt zplus       = (blockidx & 4) >> 2;
3355:                 PetscInt zcoord      = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus);
3356:                 PetscInt ycoord      = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus);
3357:                 PetscInt xcoord      = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus);
3358:                 PetscInt vert        = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert;

3360:                 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert;
3361:                 seen[vert]                                       = PETSC_TRUE;
3362:               }
3363:             }
3364:           }
3365:         }
3366:       }
3367:       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++)
3368:         if (seen[i]) numVertices++;
3369:       count = 0;
3370:       PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert));
3371:       PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords));
3372:       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1;
3373:       for (PetscInt k = 0; k < extentPlus[2]; k++) {
3374:         for (PetscInt j = 0; j < extentPlus[1]; j++) {
3375:           for (PetscInt i = 0; i < extentPlus[0]; i++) {
3376:             for (PetscInt v = 0; v < vertsPerBlock; v++) {
3377:               PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v;

3379:               if (seen[vIdx]) {
3380:                 PetscInt thisVert;

3382:                 vertToTrueVert[vIdx] = thisVert = count++;

3384:                 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d];
3385:                 vtxCoords[3 * thisVert + 0] += i * 2;
3386:                 vtxCoords[3 * thisVert + 1] += j * 2;
3387:                 vtxCoords[3 * thisVert + 2] += k * 2;
3388:               }
3389:             }
3390:           }
3391:         }
3392:       }
3393:       for (PetscInt i = 0; i < numBlocks; i++) {
3394:         for (PetscInt f = 0; f < facesPerBlock; f++) {
3395:           for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]];
3396:         }
3397:       }
3398:       PetscCall(PetscFree(vertToTrueVert));
3399:       PetscCall(PetscFree(seen));
3400:       cells_flat = cells[0][0];
3401:       numEdges   = 0;
3402:       for (PetscInt i = 0; i < numFaces; i++) {
3403:         for (PetscInt e = 0; e < 4; e++) {
3404:           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
3405:           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};

3407:           for (PetscInt d = 0; d < 3; d++) {
3408:             if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) {
3409:               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++;
3410:               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++;
3411:             }
3412:           }
3413:         }
3414:       }
3415:       PetscCall(PetscMalloc1(numEdges, &edges));
3416:       PetscCall(PetscMalloc1(numEdges, &edgeSets));
3417:       for (PetscInt edge = 0, i = 0; i < numFaces; i++) {
3418:         for (PetscInt e = 0; e < 4; e++) {
3419:           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
3420:           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};

3422:           for (PetscInt d = 0; d < 3; d++) {
3423:             if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) {
3424:               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) {
3425:                 edges[edge][0]   = ev[0];
3426:                 edges[edge][1]   = ev[1];
3427:                 edgeSets[edge++] = 2 * d;
3428:               }
3429:               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) {
3430:                 edges[edge][0]   = ev[0];
3431:                 edges[edge][1]   = ev[1];
3432:                 edgeSets[edge++] = 2 * d + 1;
3433:               }
3434:             }
3435:           }
3436:         }
3437:       }
3438:     }
3439:     evalFunc   = TPSEvaluate_Gyroid;
3440:     normalFunc = TPSExtrudeNormalFunc_Gyroid;
3441:     break;
3442:   }

3444:   PetscCall(DMSetDimension(dm, topoDim));
3445:   if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat));
3446:   else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL));
3447:   PetscCall(PetscFree(cells_flat));
3448:   {
3449:     DM idm;
3450:     PetscCall(DMPlexInterpolate(dm, &idm));
3451:     PetscCall(DMPlexReplace_Internal(dm, &idm));
3452:   }
3453:   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords));
3454:   else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL));
3455:   PetscCall(PetscFree(vtxCoords));

3457:   PetscCall(DMCreateLabel(dm, "Face Sets"));
3458:   PetscCall(DMGetLabel(dm, "Face Sets", &label));
3459:   for (PetscInt e = 0; e < numEdges; e++) {
3460:     PetscInt        njoin;
3461:     const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]};
3462:     PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join));
3463:     PetscCheck(njoin == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected unique join of vertices %" PetscInt_FMT " and %" PetscInt_FMT, edges[e][0], edges[e][1]);
3464:     PetscCall(DMLabelSetValue(label, join[0], edgeSets[e]));
3465:     PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join));
3466:   }
3467:   PetscCall(PetscFree(edges));
3468:   PetscCall(PetscFree(edgeSets));
3469:   if (tps_distribute) {
3470:     DM               pdm = NULL;
3471:     PetscPartitioner part;

3473:     PetscCall(DMPlexGetPartitioner(dm, &part));
3474:     PetscCall(PetscPartitionerSetFromOptions(part));
3475:     PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm));
3476:     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
3477:     // Do not auto-distribute again
3478:     PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
3479:   }

3481:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
3482:   for (PetscInt refine = 0; refine < refinements; refine++) {
3483:     PetscInt     m;
3484:     DM           dmf;
3485:     Vec          X;
3486:     PetscScalar *x;
3487:     PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf));
3488:     PetscCall(DMPlexReplace_Internal(dm, &dmf));

3490:     PetscCall(DMGetCoordinatesLocal(dm, &X));
3491:     PetscCall(VecGetLocalSize(X, &m));
3492:     PetscCall(VecGetArray(X, &x));
3493:     for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i]));
3494:     PetscCall(VecRestoreArray(X, &x));
3495:   }

3497:   // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices.
3498:   PetscCall(DMGetLabel(dm, "Face Sets", &label));
3499:   PetscCall(DMPlexLabelComplete(dm, label));

3501:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));

3503:   if (thickness > 0) {
3504:     DM              edm, cdm, ecdm;
3505:     DMPlexTransform tr;
3506:     const char     *prefix;
3507:     PetscOptions    options;
3508:     // Code from DMPlexExtrude
3509:     PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
3510:     PetscCall(DMPlexTransformSetDM(tr, dm));
3511:     PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDE));
3512:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
3513:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
3514:     PetscCall(PetscObjectGetOptions((PetscObject)dm, &options));
3515:     PetscCall(PetscObjectSetOptions((PetscObject)tr, options));
3516:     PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers));
3517:     PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness));
3518:     PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE));
3519:     PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE));
3520:     PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc));
3521:     PetscCall(DMPlexTransformSetFromOptions(tr));
3522:     PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL));
3523:     PetscCall(DMPlexTransformSetUp(tr));
3524:     PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view"));
3525:     PetscCall(DMPlexTransformApply(tr, dm, &edm));
3526:     PetscCall(DMCopyDisc(dm, edm));
3527:     PetscCall(DMGetCoordinateDM(dm, &cdm));
3528:     PetscCall(DMGetCoordinateDM(edm, &ecdm));
3529:     PetscCall(DMCopyDisc(cdm, ecdm));
3530:     PetscCall(DMPlexTransformCreateDiscLabels(tr, edm));
3531:     PetscCall(DMPlexTransformDestroy(&tr));
3532:     if (edm) {
3533:       ((DM_Plex *)edm->data)->printFEM    = ((DM_Plex *)dm->data)->printFEM;
3534:       ((DM_Plex *)edm->data)->printL2     = ((DM_Plex *)dm->data)->printL2;
3535:       ((DM_Plex *)edm->data)->printLocate = ((DM_Plex *)dm->data)->printLocate;
3536:     }
3537:     PetscCall(DMPlexReplace_Internal(dm, &edm));
3538:   }
3539:   PetscFunctionReturn(PETSC_SUCCESS);
3540: }

3542: /*@
3543:   DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface

3545:   Collective

3547:   Input Parameters:
3548: + comm           - The communicator for the `DM` object
3549: . tpstype        - Type of triply-periodic surface
3550: . extent         - Array of length 3 containing number of periods in each direction
3551: . periodic       - array of length 3 with periodicity, or `NULL` for non-periodic
3552: . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable)
3553: . refinements    - Number of factor-of-2 refinements of 2D manifold mesh
3554: . layers         - Number of cell layers extruded in normal direction
3555: - thickness      - Thickness in normal direction

3557:   Output Parameter:
3558: . dm - The `DM` object

3560:   Level: beginner

3562:   Notes:
3563:   This meshes the surface of the Schwarz P or Gyroid surfaces.  Schwarz P is the simplest member of the triply-periodic minimal surfaces.
3564:   <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries.
3565:   The Gyroid <https://en.wikipedia.org/wiki/Gyroid> is another triply-periodic minimal surface with applications in additive manufacturing; it is much more difficult to "cut" since there are no planes of symmetry.
3566:   Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested.
3567:   On each refinement, all vertices are projected to their nearest point on the surface.
3568:   This projection could readily be extended to related surfaces.

3570:   See {cite}`maskery2018insights`

3572:   The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$.
3573:   When the mesh is refined, "Face Sets" contain the new vertices (created during refinement).
3574:   Use `DMPlexLabelComplete()` to propagate to coarse-level vertices.

3576:   Developer Notes:
3577:   The Gyroid mesh does not currently mark boundary sets.

3579: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()`
3580: @*/
3581: PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm)
3582: {
3583:   PetscFunctionBegin;
3584:   PetscCall(DMCreate(comm, dm));
3585:   PetscCall(DMSetType(*dm, DMPLEX));
3586:   PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness));
3587:   PetscFunctionReturn(PETSC_SUCCESS);
3588: }

3590: /*@
3591:   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.

3593:   Collective

3595:   Input Parameters:
3596: + comm    - The communicator for the `DM` object
3597: . dim     - The dimension
3598: . simplex - Use simplices, or tensor product cells
3599: - R       - The radius

3601:   Output Parameter:
3602: . dm - The `DM` object

3604:   Level: beginner

3606: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3607: @*/
3608: PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm)
3609: {
3610:   PetscFunctionBegin;
3611:   PetscAssertPointer(dm, 5);
3612:   PetscCall(DMCreate(comm, dm));
3613:   PetscCall(DMSetType(*dm, DMPLEX));
3614:   PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R));
3615:   PetscFunctionReturn(PETSC_SUCCESS);
3616: }

3618: static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R)
3619: {
3620:   DM          sdm, vol;
3621:   DMLabel     bdlabel;
3622:   const char *prefix;

3624:   PetscFunctionBegin;
3625:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
3626:   PetscCall(DMSetType(sdm, DMPLEX));
3627:   PetscCall(DMGetOptionsPrefix(dm, &prefix));
3628:   PetscCall(DMSetOptionsPrefix(sdm, prefix));
3629:   PetscCall(DMAppendOptionsPrefix(sdm, "bd_"));
3630:   PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE));
3631:   PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R));
3632:   PetscCall(DMSetFromOptions(sdm));
3633:   PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view"));
3634:   PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol));
3635:   PetscCall(DMDestroy(&sdm));
3636:   PetscCall(DMPlexReplace_Internal(dm, &vol));
3637:   PetscCall(DMCreateLabel(dm, "marker"));
3638:   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
3639:   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
3640:   PetscCall(DMPlexLabelComplete(dm, bdlabel));
3641:   PetscFunctionReturn(PETSC_SUCCESS);
3642: }

3644: /*@
3645:   DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d.

3647:   Collective

3649:   Input Parameters:
3650: + comm - The communicator for the `DM` object
3651: . dim  - The dimension
3652: - R    - The radius

3654:   Output Parameter:
3655: . dm - The `DM` object

3657:   Options Database Key:
3658: . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry

3660:   Level: beginner

3662: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3663: @*/
3664: PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm)
3665: {
3666:   PetscFunctionBegin;
3667:   PetscCall(DMCreate(comm, dm));
3668:   PetscCall(DMSetType(*dm, DMPLEX));
3669:   PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R));
3670:   PetscFunctionReturn(PETSC_SUCCESS);
3671: }

3673: static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct)
3674: {
3675:   PetscFunctionBegin;
3676:   switch (ct) {
3677:   case DM_POLYTOPE_POINT: {
3678:     PetscInt    numPoints[1]        = {1};
3679:     PetscInt    coneSize[1]         = {0};
3680:     PetscInt    cones[1]            = {0};
3681:     PetscInt    coneOrientations[1] = {0};
3682:     PetscScalar vertexCoords[1]     = {0.0};

3684:     PetscCall(DMSetDimension(rdm, 0));
3685:     PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3686:   } break;
3687:   case DM_POLYTOPE_SEGMENT: {
3688:     PetscInt    numPoints[2]        = {2, 1};
3689:     PetscInt    coneSize[3]         = {2, 0, 0};
3690:     PetscInt    cones[2]            = {1, 2};
3691:     PetscInt    coneOrientations[2] = {0, 0};
3692:     PetscScalar vertexCoords[2]     = {-1.0, 1.0};

3694:     PetscCall(DMSetDimension(rdm, 1));
3695:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3696:   } break;
3697:   case DM_POLYTOPE_POINT_PRISM_TENSOR: {
3698:     PetscInt    numPoints[2]        = {2, 1};
3699:     PetscInt    coneSize[3]         = {2, 0, 0};
3700:     PetscInt    cones[2]            = {1, 2};
3701:     PetscInt    coneOrientations[2] = {0, 0};
3702:     PetscScalar vertexCoords[2]     = {-1.0, 1.0};

3704:     PetscCall(DMSetDimension(rdm, 1));
3705:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3706:   } break;
3707:   case DM_POLYTOPE_TRIANGLE: {
3708:     PetscInt    numPoints[2]        = {3, 1};
3709:     PetscInt    coneSize[4]         = {3, 0, 0, 0};
3710:     PetscInt    cones[3]            = {1, 2, 3};
3711:     PetscInt    coneOrientations[3] = {0, 0, 0};
3712:     PetscScalar vertexCoords[6]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0};

3714:     PetscCall(DMSetDimension(rdm, 2));
3715:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3716:   } break;
3717:   case DM_POLYTOPE_QUADRILATERAL: {
3718:     PetscInt    numPoints[2]        = {4, 1};
3719:     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3720:     PetscInt    cones[4]            = {1, 2, 3, 4};
3721:     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3722:     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0};

3724:     PetscCall(DMSetDimension(rdm, 2));
3725:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3726:   } break;
3727:   case DM_POLYTOPE_SEG_PRISM_TENSOR: {
3728:     PetscInt    numPoints[2]        = {4, 1};
3729:     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3730:     PetscInt    cones[4]            = {1, 2, 3, 4};
3731:     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3732:     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};

3734:     PetscCall(DMSetDimension(rdm, 2));
3735:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3736:   } break;
3737:   case DM_POLYTOPE_TETRAHEDRON: {
3738:     PetscInt    numPoints[2]        = {4, 1};
3739:     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3740:     PetscInt    cones[4]            = {1, 2, 3, 4};
3741:     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3742:     PetscScalar vertexCoords[12]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0};

3744:     PetscCall(DMSetDimension(rdm, 3));
3745:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3746:   } break;
3747:   case DM_POLYTOPE_HEXAHEDRON: {
3748:     PetscInt    numPoints[2]        = {8, 1};
3749:     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3750:     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3751:     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3752:     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};

3754:     PetscCall(DMSetDimension(rdm, 3));
3755:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3756:   } break;
3757:   case DM_POLYTOPE_TRI_PRISM: {
3758:     PetscInt    numPoints[2]        = {6, 1};
3759:     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3760:     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3761:     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3762:     PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0};

3764:     PetscCall(DMSetDimension(rdm, 3));
3765:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3766:   } break;
3767:   case DM_POLYTOPE_TRI_PRISM_TENSOR: {
3768:     PetscInt    numPoints[2]        = {6, 1};
3769:     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3770:     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3771:     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3772:     PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0};

3774:     PetscCall(DMSetDimension(rdm, 3));
3775:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3776:   } break;
3777:   case DM_POLYTOPE_QUAD_PRISM_TENSOR: {
3778:     PetscInt    numPoints[2]        = {8, 1};
3779:     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3780:     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3781:     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3782:     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};

3784:     PetscCall(DMSetDimension(rdm, 3));
3785:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3786:   } break;
3787:   case DM_POLYTOPE_PYRAMID: {
3788:     PetscInt    numPoints[2]        = {5, 1};
3789:     PetscInt    coneSize[6]         = {5, 0, 0, 0, 0, 0};
3790:     PetscInt    cones[5]            = {1, 2, 3, 4, 5};
3791:     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3792:     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0};

3794:     PetscCall(DMSetDimension(rdm, 3));
3795:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3796:   } break;
3797:   default:
3798:     SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]);
3799:   }
3800:   {
3801:     PetscInt Nv, v;

3803:     /* Must create the celltype label here so that we do not automatically try to compute the types */
3804:     PetscCall(DMCreateLabel(rdm, "celltype"));
3805:     PetscCall(DMPlexSetCellType(rdm, 0, ct));
3806:     PetscCall(DMPlexGetChart(rdm, NULL, &Nv));
3807:     for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT));
3808:   }
3809:   PetscCall(DMPlexInterpolateInPlace_Internal(rdm));
3810:   PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct]));
3811:   PetscFunctionReturn(PETSC_SUCCESS);
3812: }

3814: /*@
3815:   DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell

3817:   Collective

3819:   Input Parameters:
3820: + comm - The communicator
3821: - ct   - The cell type of the reference cell

3823:   Output Parameter:
3824: . refdm - The reference cell

3826:   Level: intermediate

3828: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`
3829: @*/
3830: PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm)
3831: {
3832:   PetscFunctionBegin;
3833:   PetscCall(DMCreate(comm, refdm));
3834:   PetscCall(DMSetType(*refdm, DMPLEX));
3835:   PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct));
3836:   PetscFunctionReturn(PETSC_SUCCESS);
3837: }

3839: static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[])
3840: {
3841:   DM        plex;
3842:   DMLabel   label;
3843:   PetscBool hasLabel;

3845:   PetscFunctionBegin;
3846:   PetscCall(DMHasLabel(dm, name, &hasLabel));
3847:   if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS);
3848:   PetscCall(DMCreateLabel(dm, name));
3849:   PetscCall(DMGetLabel(dm, name, &label));
3850:   PetscCall(DMConvert(dm, DMPLEX, &plex));
3851:   PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label));
3852:   PetscCall(DMPlexLabelComplete(plex, label));
3853:   PetscCall(DMDestroy(&plex));
3854:   PetscFunctionReturn(PETSC_SUCCESS);
3855: }

3857: /*
3858:   We use the last coordinate as the radius, the inner radius is lower[dim-1] and the outer radius is upper[dim-1]. Then we map the first coordinate around the circle.

3860:     (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0]))
3861: */
3862: static void boxToAnnulus(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
3863: {
3864:   const PetscReal low = PetscRealPart(constants[0]);
3865:   const PetscReal upp = PetscRealPart(constants[1]);
3866:   const PetscReal r   = PetscRealPart(u[1]);
3867:   const PetscReal th  = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low);

3869:   f0[0] = r * PetscCosReal(th);
3870:   f0[1] = r * PetscSinReal(th);
3871: }

3873: PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg);

3875: const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL};

3877: static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems *PetscOptionsObject, PetscBool *useCoordSpace, DM dm)
3878: {
3879:   DMPlexShape    shape   = DM_SHAPE_BOX;
3880:   DMPolytopeType cell    = DM_POLYTOPE_TRIANGLE;
3881:   PetscInt       dim     = 2;
3882:   PetscBool      simplex = PETSC_TRUE, interpolate = PETSC_TRUE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE;
3883:   PetscBool      flg, flg2, fflg, strflg, bdfflg, nameflg;
3884:   MPI_Comm       comm;
3885:   char           filename[PETSC_MAX_PATH_LEN]   = "<unspecified>";
3886:   char           bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>";
3887:   char           plexname[PETSC_MAX_PATH_LEN]   = "";
3888:   const char    *option;

3890:   PetscFunctionBegin;
3891:   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
3892:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3893:   /* TODO Turn this into a registration interface */
3894:   PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg));
3895:   PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg));
3896:   PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg));
3897:   PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg));
3898:   PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL));
3899:   PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL));
3900:   PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg));
3901:   PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0));
3902:   PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg));
3903:   PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg));
3904:   PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg));
3905:   PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2));
3906:   if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure));

3908:   switch (cell) {
3909:   case DM_POLYTOPE_POINT:
3910:   case DM_POLYTOPE_SEGMENT:
3911:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
3912:   case DM_POLYTOPE_TRIANGLE:
3913:   case DM_POLYTOPE_QUADRILATERAL:
3914:   case DM_POLYTOPE_TETRAHEDRON:
3915:   case DM_POLYTOPE_HEXAHEDRON:
3916:     *useCoordSpace = PETSC_TRUE;
3917:     break;
3918:   default:
3919:     *useCoordSpace = PETSC_FALSE;
3920:     break;
3921:   }

3923:   if (fflg) {
3924:     DM dmnew;

3926:     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, plexname, interpolate, &dmnew));
3927:     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3928:     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3929:   } else if (refDomain) {
3930:     PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell));
3931:   } else if (bdfflg) {
3932:     DM bdm, dmnew;

3934:     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, plexname, interpolate, &bdm));
3935:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_"));
3936:     PetscCall(DMSetFromOptions(bdm));
3937:     PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew));
3938:     PetscCall(DMDestroy(&bdm));
3939:     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3940:     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3941:   } else if (strflg) {
3942:     DM            dmnew;
3943:     PetscViewer   viewer;
3944:     const char   *contents;
3945:     char         *strname;
3946:     char          tmpdir[PETSC_MAX_PATH_LEN];
3947:     char          tmpfilename[PETSC_MAX_PATH_LEN];
3948:     char          name[PETSC_MAX_PATH_LEN];
3949:     PetscObjectId id;
3950:     MPI_Comm      comm;
3951:     PetscMPIInt   rank;

3953:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3954:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
3955:     PetscCall(PetscStrchr(filename, ':', &strname));
3956:     PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename);
3957:     strname[0] = '\0';
3958:     ++strname;
3959:     PetscCall(PetscDLSym(NULL, strname, (void **)&contents));
3960:     PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname);
3961:     PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN));
3962:     PetscCall(PetscObjectGetId((PetscObject)dm, &id));
3963:     PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh_%d.%s", tmpdir, (int)id, filename));
3964:     PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer));
3965:     PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents));
3966:     PetscCall(PetscViewerDestroy(&viewer));
3967:     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew));
3968:     if (!rank) PetscCheck(!unlink(tmpfilename), comm, PETSC_ERR_FILE_UNEXPECTED, "Could not delete file: %s due to \"%s\"", tmpfilename, strerror(errno));
3969:     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname));
3970:     PetscCall(PetscObjectSetName((PetscObject)dm, name));
3971:     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3972:     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3973:   } else {
3974:     PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape]));
3975:     switch (shape) {
3976:     case DM_SHAPE_BOX:
3977:     case DM_SHAPE_ZBOX:
3978:     case DM_SHAPE_ANNULUS: {
3979:       PetscInt       faces[3]  = {0, 0, 0};
3980:       PetscReal      lower[3]  = {0, 0, 0};
3981:       PetscReal      upper[3]  = {1, 1, 1};
3982:       DMBoundaryType bdt[3]    = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
3983:       PetscBool      isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE;
3984:       PetscInt       i, n;

3986:       n = dim;
3987:       for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim);
3988:       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
3989:       n = 3;
3990:       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
3991:       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3992:       n = 3;
3993:       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
3994:       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3995:       n = 3;
3996:       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
3997:       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);

3999:       PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented");
4000:       if (isAnnular)
4001:         for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC;

4003:       switch (cell) {
4004:       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4005:         PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt));
4006:         if (!interpolate) {
4007:           DM udm;

4009:           PetscCall(DMPlexUninterpolate(dm, &udm));
4010:           PetscCall(DMPlexReplace_Internal(dm, &udm));
4011:         }
4012:         break;
4013:       default:
4014:         PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate));
4015:         break;
4016:       }
4017:       if (isAnnular) {
4018:         DM          cdm;
4019:         PetscDS     cds;
4020:         PetscScalar bounds[2] = {lower[0], upper[0]};

4022:         // Fix coordinates for annular region
4023:         PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
4024:         PetscCall(DMSetCellCoordinatesLocal(dm, NULL));
4025:         PetscCall(DMSetCellCoordinates(dm, NULL));
4026:         PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL));
4027:         PetscCall(DMGetCoordinateDM(dm, &cdm));
4028:         PetscCall(DMGetDS(cdm, &cds));
4029:         PetscCall(PetscDSSetConstants(cds, 2, bounds));
4030:         PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus));
4031:       }
4032:     } break;
4033:     case DM_SHAPE_BOX_SURFACE: {
4034:       PetscInt  faces[3] = {0, 0, 0};
4035:       PetscReal lower[3] = {0, 0, 0};
4036:       PetscReal upper[3] = {1, 1, 1};
4037:       PetscInt  i, n;

4039:       n = dim + 1;
4040:       for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1));
4041:       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
4042:       n = 3;
4043:       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4044:       PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1);
4045:       n = 3;
4046:       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4047:       PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1);
4048:       PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate));
4049:     } break;
4050:     case DM_SHAPE_SPHERE: {
4051:       PetscReal R = 1.0;

4053:       PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg));
4054:       PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R));
4055:     } break;
4056:     case DM_SHAPE_BALL: {
4057:       PetscReal R = 1.0;

4059:       PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg));
4060:       PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R));
4061:     } break;
4062:     case DM_SHAPE_CYLINDER: {
4063:       DMBoundaryType bdt = DM_BOUNDARY_NONE;
4064:       PetscInt       Nw  = 6;

4066:       PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL));
4067:       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL));
4068:       switch (cell) {
4069:       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4070:         PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate));
4071:         break;
4072:       default:
4073:         PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt));
4074:         break;
4075:       }
4076:     } break;
4077:     case DM_SHAPE_SCHWARZ_P: // fallthrough
4078:     case DM_SHAPE_GYROID: {
4079:       PetscInt       extent[3] = {1, 1, 1}, refine = 0, layers = 0, three;
4080:       PetscReal      thickness   = 0.;
4081:       DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
4082:       DMPlexTPSType  tps_type    = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID;
4083:       PetscBool      tps_distribute;
4084:       PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL));
4085:       PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL));
4086:       PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL));
4087:       PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL));
4088:       PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL));
4089:       PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute));
4090:       PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL));
4091:       PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness));
4092:     } break;
4093:     case DM_SHAPE_DOUBLET: {
4094:       DM        dmnew;
4095:       PetscReal rl = 0.0;

4097:       PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL));
4098:       PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew));
4099:       PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4100:       PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4101:     } break;
4102:     case DM_SHAPE_HYPERCUBIC: {
4103:       PetscInt       *edges;
4104:       PetscReal      *lower, *upper;
4105:       DMBoundaryType *bdt;
4106:       PetscInt        n, d;

4108:       *useCoordSpace = PETSC_FALSE;
4109:       PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt));
4110:       for (d = 0; d < dim; ++d) {
4111:         edges[d] = 1;
4112:         lower[d] = 0.;
4113:         upper[d] = 1.;
4114:         bdt[d]   = DM_BOUNDARY_PERIODIC;
4115:       }
4116:       n = dim;
4117:       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg));
4118:       n = dim;
4119:       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4120:       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4121:       n = dim;
4122:       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4123:       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4124:       n = dim;
4125:       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
4126:       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4127:       PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt));
4128:       PetscCall(PetscFree4(edges, lower, upper, bdt));
4129:     } break;
4130:     default:
4131:       SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]);
4132:     }
4133:   }
4134:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4135:   if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname));
4136:   // Allow label creation
4137:   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg));
4138:   if (flg) {
4139:     DMLabel     label;
4140:     PetscInt    points[1024], n = 1024;
4141:     char        fulloption[PETSC_MAX_PATH_LEN];
4142:     const char *name = &option[14];

4144:     PetscCall(DMCreateLabel(dm, name));
4145:     PetscCall(DMGetLabel(dm, name, &label));
4146:     fulloption[0] = '-';
4147:     fulloption[1] = 0;
4148:     PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN));
4149:     PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL));
4150:     for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1));
4151:   }
4152:   // Allow cohesive label creation
4153:   //   Faces are input, completed, and all points are marked with their depth
4154:   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg));
4155:   if (flg) {
4156:     DMLabel  label;
4157:     PetscInt points[1024], n, pStart, pEnd, Nl = 1;
4158:     char     fulloption[PETSC_MAX_PATH_LEN];
4159:     char     name[PETSC_MAX_PATH_LEN];
4160:     size_t   len;

4162:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4163:     PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN));
4164:     PetscCall(PetscStrlen(name, &len));
4165:     if (name[len - 1] == '0') Nl = 10;
4166:     for (PetscInt l = 0; l < Nl; ++l) {
4167:       if (l > 0) name[len - 1] = '0' + l;
4168:       fulloption[0] = 0;
4169:       PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32));
4170:       PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32));
4171:       n = 1024;
4172:       PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg));
4173:       if (!flg) break;
4174:       PetscCall(DMCreateLabel(dm, name));
4175:       PetscCall(DMGetLabel(dm, name, &label));
4176:       if (pStart >= pEnd) n = 0;
4177:       for (PetscInt p = 0; p < n; ++p) {
4178:         const PetscInt point   = points[p];
4179:         PetscInt      *closure = NULL;
4180:         PetscInt       clSize, pdepth;

4182:         PetscCall(DMPlexGetPointDepth(dm, point, &pdepth));
4183:         PetscCall(DMLabelSetValue(label, point, pdepth));
4184:         PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
4185:         for (PetscInt cl = 0; cl < clSize * 2; cl += 2) {
4186:           PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth));
4187:           PetscCall(DMLabelSetValue(label, closure[cl], pdepth));
4188:         }
4189:         PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
4190:       }
4191:       PetscCall(DMPlexOrientLabel(dm, label));
4192:       PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL));
4193:     }
4194:   }
4195:   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
4196:   PetscFunctionReturn(PETSC_SUCCESS);
4197: }

4199: PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject)
4200: {
4201:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4202:   PetscBool flg, flg2;
4203:   char      bdLabel[PETSC_MAX_PATH_LEN];
4204:   char      method[PETSC_MAX_PATH_LEN];

4206:   PetscFunctionBegin;
4207:   /* Handle viewing */
4208:   PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL));
4209:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0));
4210:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0));
4211:   PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL));
4212:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0));
4213:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0));
4214:   PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg));
4215:   if (flg) PetscCall(PetscLogDefaultBegin());
4216:   /* Labeling */
4217:   PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg));
4218:   if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel));
4219:   /* Point Location */
4220:   PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL));
4221:   /* Partitioning and distribution */
4222:   PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL));
4223:   /* Reordering */
4224:   PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg));
4225:   if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE));
4226:   PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg));
4227:   if (flg) PetscCall(DMReorderSectionSetType(dm, method));
4228:   /* Generation and remeshing */
4229:   PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL));
4230:   /* Projection behavior */
4231:   PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0));
4232:   PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL));
4233:   /* Checking structure */
4234:   {
4235:     PetscBool all = PETSC_FALSE;

4237:     PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL));
4238:     if (all) {
4239:       PetscCall(DMPlexCheck(dm));
4240:     } else {
4241:       PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2));
4242:       if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm));
4243:       PetscCall(PetscOptionsBool("-dm_plex_check_skeleton", "Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes)", "DMPlexCheckSkeleton", PETSC_FALSE, &flg, &flg2));
4244:       if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0));
4245:       PetscCall(PetscOptionsBool("-dm_plex_check_faces", "Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type", "DMPlexCheckFaces", PETSC_FALSE, &flg, &flg2));
4246:       if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0));
4247:       PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2));
4248:       if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm));
4249:       PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2));
4250:       if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
4251:       PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2));
4252:       if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm));
4253:     }
4254:     PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2));
4255:     if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE));
4256:   }
4257:   {
4258:     PetscReal scale = 1.0;

4260:     PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg));
4261:     if (flg) {
4262:       Vec coordinates, coordinatesLocal;

4264:       PetscCall(DMGetCoordinates(dm, &coordinates));
4265:       PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
4266:       PetscCall(VecScale(coordinates, scale));
4267:       PetscCall(VecScale(coordinatesLocal, scale));
4268:     }
4269:   }
4270:   PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner));
4271:   PetscFunctionReturn(PETSC_SUCCESS);
4272: }

4274: PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap)
4275: {
4276:   PetscInt  numOvLabels = 16, numOvExLabels = 16;
4277:   char     *ovLabelNames[16], *ovExLabelNames[16];
4278:   PetscInt  numOvValues = 16, numOvExValues = 16, l;
4279:   PetscBool flg;

4281:   PetscFunctionBegin;
4282:   PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0));
4283:   PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg));
4284:   if (!flg) numOvLabels = 0;
4285:   if (numOvLabels) {
4286:     ((DM_Plex *)dm->data)->numOvLabels = numOvLabels;
4287:     for (l = 0; l < numOvLabels; ++l) {
4288:       PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l]));
4289:       PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]);
4290:       PetscCall(PetscFree(ovLabelNames[l]));
4291:     }
4292:     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg));
4293:     if (!flg) numOvValues = 0;
4294:     PetscCheck(numOvLabels == numOvValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvLabels, numOvValues);

4296:     PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg));
4297:     if (!flg) numOvExLabels = 0;
4298:     ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels;
4299:     for (l = 0; l < numOvExLabels; ++l) {
4300:       PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l]));
4301:       PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]);
4302:       PetscCall(PetscFree(ovExLabelNames[l]));
4303:     }
4304:     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg));
4305:     if (!flg) numOvExValues = 0;
4306:     PetscCheck(numOvExLabels == numOvExValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of exclude labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvExLabels, numOvExValues);
4307:   }
4308:   PetscFunctionReturn(PETSC_SUCCESS);
4309: }

4311: static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject)
4312: {
4313:   PetscFunctionList    ordlist;
4314:   char                 oname[256];
4315:   char                 sublabelname[PETSC_MAX_PATH_LEN] = "";
4316:   DMReorderDefaultFlag reorder;
4317:   PetscReal            volume    = -1.0;
4318:   PetscInt             prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim;
4319:   PetscBool uniformOrig = PETSC_FALSE, created = PETSC_FALSE, uniform = PETSC_TRUE, distribute, saveSF = PETSC_FALSE, interpolate = PETSC_TRUE, coordSpace = PETSC_TRUE, remap = PETSC_TRUE, ghostCells = PETSC_FALSE, isHierarchy, ignoreModel = PETSC_FALSE, flg;

4321:   PetscFunctionBegin;
4322:   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options");
4323:   if (dm->cloneOpts) goto non_refine;
4324:   /* Handle automatic creation */
4325:   PetscCall(DMGetDimension(dm, &dim));
4326:   if (dim < 0) {
4327:     PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm));
4328:     created = PETSC_TRUE;
4329:   }
4330:   PetscCall(DMGetDimension(dm, &dim));
4331:   /* Handle interpolation before distribution */
4332:   PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg));
4333:   if (flg) {
4334:     DMPlexInterpolatedFlag interpolated;

4336:     PetscCall(DMPlexIsInterpolated(dm, &interpolated));
4337:     if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) {
4338:       DM udm;

4340:       PetscCall(DMPlexUninterpolate(dm, &udm));
4341:       PetscCall(DMPlexReplace_Internal(dm, &udm));
4342:     } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) {
4343:       DM idm;

4345:       PetscCall(DMPlexInterpolate(dm, &idm));
4346:       PetscCall(DMPlexReplace_Internal(dm, &idm));
4347:     }
4348:   }
4349:   // Handle submesh selection before distribution
4350:   PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg));
4351:   if (flg) {
4352:     DM              subdm;
4353:     DMLabel         label;
4354:     IS              valueIS, pointIS;
4355:     const PetscInt *values, *points;
4356:     PetscBool       markedFaces = PETSC_FALSE;
4357:     PetscInt        Nv, value, Np;

4359:     PetscCall(DMGetLabel(dm, sublabelname, &label));
4360:     PetscCall(DMLabelGetNumValues(label, &Nv));
4361:     PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv);
4362:     PetscCall(DMLabelGetValueIS(label, &valueIS));
4363:     PetscCall(ISGetIndices(valueIS, &values));
4364:     value = values[0];
4365:     PetscCall(ISRestoreIndices(valueIS, &values));
4366:     PetscCall(ISDestroy(&valueIS));
4367:     PetscCall(DMLabelGetStratumSize(label, value, &Np));
4368:     PetscCall(DMLabelGetStratumIS(label, value, &pointIS));
4369:     PetscCall(ISGetIndices(pointIS, &points));
4370:     for (PetscInt p = 0; p < Np; ++p) {
4371:       PetscInt pdepth;

4373:       PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth));
4374:       if (pdepth) {
4375:         markedFaces = PETSC_TRUE;
4376:         break;
4377:       }
4378:     }
4379:     PetscCall(ISRestoreIndices(pointIS, &points));
4380:     PetscCall(ISDestroy(&pointIS));
4381:     PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm));
4382:     PetscCall(DMPlexReplace_Internal(dm, &subdm));
4383:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4384:   }
4385:   /* Handle DMPlex refinement before distribution */
4386:   PetscCall(PetscOptionsBool("-dm_refine_ignore_model", "Flag to ignore the geometry model when refining", "DMCreate", ignoreModel, &ignoreModel, &flg));
4387:   if (flg) ((DM_Plex *)dm->data)->ignoreModel = ignoreModel;
4388:   PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig));
4389:   PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0));
4390:   PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
4391:   PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg));
4392:   if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform));
4393:   PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg));
4394:   if (flg) {
4395:     PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE));
4396:     PetscCall(DMPlexSetRefinementLimit(dm, volume));
4397:     prerefine = PetscMax(prerefine, 1);
4398:   }
4399:   if (prerefine) PetscCall(DMLocalizeCoordinates(dm));
4400:   for (r = 0; r < prerefine; ++r) {
4401:     DM             rdm;
4402:     PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;

4404:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4405:     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
4406:     PetscCall(DMPlexReplace_Internal(dm, &rdm));
4407:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4408:     if (coordFunc && remap) {
4409:       PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4410:       ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4411:     }
4412:   }
4413:   PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig));
4414:   /* Handle DMPlex extrusion before distribution */
4415:   PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0));
4416:   if (extLayers) {
4417:     DM edm;

4419:     PetscCall(DMExtrude(dm, extLayers, &edm));
4420:     PetscCall(DMPlexReplace_Internal(dm, &edm));
4421:     ((DM_Plex *)dm->data)->coordFunc = NULL;
4422:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4423:     extLayers = 0;
4424:     PetscCall(DMGetDimension(dm, &dim));
4425:   }
4426:   /* Handle DMPlex reordering before distribution */
4427:   PetscCall(DMPlexReorderGetDefault(dm, &reorder));
4428:   PetscCall(MatGetOrderingList(&ordlist));
4429:   PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname)));
4430:   PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg));
4431:   if (reorder == DM_REORDER_DEFAULT_TRUE || flg) {
4432:     DM pdm;
4433:     IS perm;

4435:     PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm));
4436:     PetscCall(DMPlexPermute(dm, perm, &pdm));
4437:     PetscCall(ISDestroy(&perm));
4438:     PetscCall(DMPlexReplace_Internal(dm, &pdm));
4439:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4440:   }
4441:   /* Handle DMPlex distribution */
4442:   PetscCall(DMPlexDistributeGetDefault(dm, &distribute));
4443:   PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL));
4444:   PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL));
4445:   PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
4446:   if (distribute) {
4447:     DM               pdm = NULL;
4448:     PetscPartitioner part;
4449:     PetscSF          sfMigration;

4451:     PetscCall(DMPlexGetPartitioner(dm, &part));
4452:     PetscCall(PetscPartitionerSetFromOptions(part));
4453:     PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm));
4454:     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
4455:     if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration));
4456:     PetscCall(PetscSFDestroy(&sfMigration));
4457:   }
4458:   /* Must check CEED options before creating function space for coordinates */
4459:   {
4460:     PetscBool useCeed = PETSC_FALSE, flg;

4462:     PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg));
4463:     if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed));
4464:   }
4465:   /* Create coordinate space */
4466:   if (created) {
4467:     DM_Plex  *mesh   = (DM_Plex *)dm->data;
4468:     PetscInt  degree = 1, deg;
4469:     PetscInt  height = 0;
4470:     DM        cdm;
4471:     PetscBool flg, localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE;

4473:     PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg));
4474:     PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, &degree, NULL));
4475:     PetscCall(DMGetCoordinateDegree_Internal(dm, &deg));
4476:     if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, mesh->coordFunc));
4477:     PetscCall(DMGetCoordinateDM(dm, &cdm));
4478:     if (flg && !coordSpace) {
4479:       PetscDS      cds;
4480:       PetscObject  obj;
4481:       PetscClassId id;

4483:       PetscCall(DMGetDS(cdm, &cds));
4484:       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
4485:       PetscCall(PetscObjectGetClassId(obj, &id));
4486:       if (id == PETSCFE_CLASSID) {
4487:         PetscContainer dummy;

4489:         PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy));
4490:         PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates"));
4491:         PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy));
4492:         PetscCall(PetscContainerDestroy(&dummy));
4493:         PetscCall(DMClearDS(cdm));
4494:       }
4495:       mesh->coordFunc = NULL;
4496:     }
4497:     PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL));
4498:     PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg));
4499:     if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize));
4500:     PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg));
4501:     if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height));
4502:     if (localize) PetscCall(DMLocalizeCoordinates(dm));
4503:   }
4504:   /* Handle DMPlex refinement */
4505:   remap = PETSC_TRUE;
4506:   PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0));
4507:   PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
4508:   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0));
4509:   if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4510:   if (refine && isHierarchy) {
4511:     DM *dms, coarseDM;

4513:     PetscCall(DMGetCoarseDM(dm, &coarseDM));
4514:     PetscCall(PetscObjectReference((PetscObject)coarseDM));
4515:     PetscCall(PetscMalloc1(refine, &dms));
4516:     PetscCall(DMRefineHierarchy(dm, refine, dms));
4517:     /* Total hack since we do not pass in a pointer */
4518:     PetscCall(DMPlexSwap_Static(dm, dms[refine - 1]));
4519:     if (refine == 1) {
4520:       PetscCall(DMSetCoarseDM(dm, dms[0]));
4521:       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
4522:     } else {
4523:       PetscCall(DMSetCoarseDM(dm, dms[refine - 2]));
4524:       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
4525:       PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1]));
4526:       PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE));
4527:     }
4528:     PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM));
4529:     PetscCall(PetscObjectDereference((PetscObject)coarseDM));
4530:     /* Free DMs */
4531:     for (r = 0; r < refine; ++r) {
4532:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
4533:       PetscCall(DMDestroy(&dms[r]));
4534:     }
4535:     PetscCall(PetscFree(dms));
4536:   } else {
4537:     for (r = 0; r < refine; ++r) {
4538:       DM             rdm;
4539:       PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;

4541:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4542:       PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
4543:       /* Total hack since we do not pass in a pointer */
4544:       PetscCall(DMPlexReplace_Internal(dm, &rdm));
4545:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4546:       if (coordFunc && remap) {
4547:         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4548:         ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4549:       }
4550:     }
4551:   }
4552:   /* Handle DMPlex coarsening */
4553:   PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0));
4554:   PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0));
4555:   if (coarsen && isHierarchy) {
4556:     DM *dms;

4558:     PetscCall(PetscMalloc1(coarsen, &dms));
4559:     PetscCall(DMCoarsenHierarchy(dm, coarsen, dms));
4560:     /* Free DMs */
4561:     for (r = 0; r < coarsen; ++r) {
4562:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
4563:       PetscCall(DMDestroy(&dms[r]));
4564:     }
4565:     PetscCall(PetscFree(dms));
4566:   } else {
4567:     for (r = 0; r < coarsen; ++r) {
4568:       DM             cdm;
4569:       PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;

4571:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4572:       PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm));
4573:       /* Total hack since we do not pass in a pointer */
4574:       PetscCall(DMPlexReplace_Internal(dm, &cdm));
4575:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4576:       if (coordFunc) {
4577:         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4578:         ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4579:       }
4580:     }
4581:   }
4582:   // Handle coordinate remapping
4583:   remap = PETSC_FALSE;
4584:   PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL));
4585:   if (remap) {
4586:     DMPlexCoordMap map     = DM_COORD_MAP_NONE;
4587:     PetscPointFunc mapFunc = NULL;
4588:     PetscScalar    params[16];
4589:     PetscInt       Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim;
4590:     MPI_Comm       comm;

4592:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4593:     PetscCall(DMGetCoordinateDim(dm, &cdim));
4594:     PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg));
4595:     if (!flg) Np = 0;
4596:     // TODO Allow user to pass a map function by name
4597:     PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg));
4598:     if (flg) {
4599:       switch (map) {
4600:       case DM_COORD_MAP_NONE:
4601:         mapFunc = coordMap_identity;
4602:         break;
4603:       case DM_COORD_MAP_SHEAR:
4604:         mapFunc = coordMap_shear;
4605:         if (!Np) {
4606:           Np        = cdim + 1;
4607:           params[0] = 0;
4608:           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
4609:         }
4610:         PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The shear coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np);
4611:         break;
4612:       case DM_COORD_MAP_FLARE:
4613:         mapFunc = coordMap_flare;
4614:         if (!Np) {
4615:           Np        = cdim + 1;
4616:           params[0] = 0;
4617:           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
4618:         }
4619:         PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The flare coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np);
4620:         break;
4621:       case DM_COORD_MAP_ANNULUS:
4622:         mapFunc = coordMap_annulus;
4623:         if (!Np) {
4624:           Np        = 2;
4625:           params[0] = 1.;
4626:           params[1] = 2.;
4627:         }
4628:         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
4629:         break;
4630:       case DM_COORD_MAP_SHELL:
4631:         mapFunc = coordMap_shell;
4632:         if (!Np) {
4633:           Np        = 2;
4634:           params[0] = 1.;
4635:           params[1] = 2.;
4636:         }
4637:         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
4638:         break;
4639:       default:
4640:         mapFunc = coordMap_identity;
4641:       }
4642:     }
4643:     if (Np) {
4644:       DM      cdm;
4645:       PetscDS cds;

4647:       PetscCall(DMGetCoordinateDM(dm, &cdm));
4648:       PetscCall(DMGetDS(cdm, &cds));
4649:       PetscCall(PetscDSSetConstants(cds, Np, params));
4650:     }
4651:     PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc));
4652:   }
4653:   /* Handle ghost cells */
4654:   PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL));
4655:   if (ghostCells) {
4656:     DM   gdm;
4657:     char lname[PETSC_MAX_PATH_LEN];

4659:     lname[0] = '\0';
4660:     PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg));
4661:     PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm));
4662:     PetscCall(DMPlexReplace_Internal(dm, &gdm));
4663:   }
4664:   /* Handle 1D order */
4665:   if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) {
4666:     DM           cdm, rdm;
4667:     PetscDS      cds;
4668:     PetscObject  obj;
4669:     PetscClassId id = PETSC_OBJECT_CLASSID;
4670:     IS           perm;
4671:     PetscInt     Nf;
4672:     PetscBool    distributed;

4674:     PetscCall(DMPlexIsDistributed(dm, &distributed));
4675:     PetscCall(DMGetCoordinateDM(dm, &cdm));
4676:     PetscCall(DMGetDS(cdm, &cds));
4677:     PetscCall(PetscDSGetNumFields(cds, &Nf));
4678:     if (Nf) {
4679:       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
4680:       PetscCall(PetscObjectGetClassId(obj, &id));
4681:     }
4682:     if (!distributed && id != PETSCFE_CLASSID) {
4683:       PetscCall(DMPlexGetOrdering1D(dm, &perm));
4684:       PetscCall(DMPlexPermute(dm, perm, &rdm));
4685:       PetscCall(DMPlexReplace_Internal(dm, &rdm));
4686:       PetscCall(ISDestroy(&perm));
4687:     }
4688:   }
4689: /* Handle */
4690: non_refine:
4691:   PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4692:   PetscOptionsHeadEnd();
4693:   PetscFunctionReturn(PETSC_SUCCESS);
4694: }

4696: static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec)
4697: {
4698:   PetscFunctionBegin;
4699:   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
4700:   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
4701:   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex));
4702:   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native));
4703:   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex));
4704:   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native));
4705:   PetscFunctionReturn(PETSC_SUCCESS);
4706: }

4708: static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec)
4709: {
4710:   PetscFunctionBegin;
4711:   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
4712:   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local));
4713:   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local));
4714:   PetscFunctionReturn(PETSC_SUCCESS);
4715: }

4717: static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4718: {
4719:   PetscInt depth, d;

4721:   PetscFunctionBegin;
4722:   PetscCall(DMPlexGetDepth(dm, &depth));
4723:   if (depth == 1) {
4724:     PetscCall(DMGetDimension(dm, &d));
4725:     if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
4726:     else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd));
4727:     else {
4728:       *pStart = 0;
4729:       *pEnd   = 0;
4730:     }
4731:   } else {
4732:     PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
4733:   }
4734:   PetscFunctionReturn(PETSC_SUCCESS);
4735: }

4737: static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
4738: {
4739:   PetscSF            sf;
4740:   PetscInt           niranks, njranks, n;
4741:   const PetscMPIInt *iranks, *jranks;
4742:   DM_Plex           *data = (DM_Plex *)dm->data;

4744:   PetscFunctionBegin;
4745:   PetscCall(DMGetPointSF(dm, &sf));
4746:   if (!data->neighbors) {
4747:     PetscCall(PetscSFSetUp(sf));
4748:     PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL));
4749:     PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL));
4750:     PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors));
4751:     PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks));
4752:     PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks));
4753:     n = njranks + niranks;
4754:     PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1));
4755:     /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */
4756:     PetscCall(PetscMPIIntCast(n, data->neighbors));
4757:   }
4758:   if (nranks) *nranks = data->neighbors[0];
4759:   if (ranks) {
4760:     if (data->neighbors[0]) *ranks = data->neighbors + 1;
4761:     else *ranks = NULL;
4762:   }
4763:   PetscFunctionReturn(PETSC_SUCCESS);
4764: }

4766: PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec);

4768: static PetscErrorCode DMInitialize_Plex(DM dm)
4769: {
4770:   PetscFunctionBegin;
4771:   dm->ops->view                      = DMView_Plex;
4772:   dm->ops->load                      = DMLoad_Plex;
4773:   dm->ops->setfromoptions            = DMSetFromOptions_Plex;
4774:   dm->ops->clone                     = DMClone_Plex;
4775:   dm->ops->setup                     = DMSetUp_Plex;
4776:   dm->ops->createlocalsection        = DMCreateLocalSection_Plex;
4777:   dm->ops->createsectionpermutation  = DMCreateSectionPermutation_Plex;
4778:   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_Plex;
4779:   dm->ops->createglobalvector        = DMCreateGlobalVector_Plex;
4780:   dm->ops->createlocalvector         = DMCreateLocalVector_Plex;
4781:   dm->ops->getlocaltoglobalmapping   = NULL;
4782:   dm->ops->createfieldis             = NULL;
4783:   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_Plex;
4784:   dm->ops->createcoordinatefield     = DMCreateCoordinateField_Plex;
4785:   dm->ops->getcoloring               = NULL;
4786:   dm->ops->creatematrix              = DMCreateMatrix_Plex;
4787:   dm->ops->createinterpolation       = DMCreateInterpolation_Plex;
4788:   dm->ops->createmassmatrix          = DMCreateMassMatrix_Plex;
4789:   dm->ops->createmassmatrixlumped    = DMCreateMassMatrixLumped_Plex;
4790:   dm->ops->createinjection           = DMCreateInjection_Plex;
4791:   dm->ops->refine                    = DMRefine_Plex;
4792:   dm->ops->coarsen                   = DMCoarsen_Plex;
4793:   dm->ops->refinehierarchy           = DMRefineHierarchy_Plex;
4794:   dm->ops->coarsenhierarchy          = DMCoarsenHierarchy_Plex;
4795:   dm->ops->extrude                   = DMExtrude_Plex;
4796:   dm->ops->globaltolocalbegin        = NULL;
4797:   dm->ops->globaltolocalend          = NULL;
4798:   dm->ops->localtoglobalbegin        = NULL;
4799:   dm->ops->localtoglobalend          = NULL;
4800:   dm->ops->destroy                   = DMDestroy_Plex;
4801:   dm->ops->createsubdm               = DMCreateSubDM_Plex;
4802:   dm->ops->createsuperdm             = DMCreateSuperDM_Plex;
4803:   dm->ops->getdimpoints              = DMGetDimPoints_Plex;
4804:   dm->ops->locatepoints              = DMLocatePoints_Plex;
4805:   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_Plex;
4806:   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex;
4807:   dm->ops->projectfieldlocal         = DMProjectFieldLocal_Plex;
4808:   dm->ops->projectfieldlabellocal    = DMProjectFieldLabelLocal_Plex;
4809:   dm->ops->projectbdfieldlabellocal  = DMProjectBdFieldLabelLocal_Plex;
4810:   dm->ops->computel2diff             = DMComputeL2Diff_Plex;
4811:   dm->ops->computel2gradientdiff     = DMComputeL2GradientDiff_Plex;
4812:   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_Plex;
4813:   dm->ops->getneighbors              = DMGetNeighbors_Plex;
4814:   dm->ops->getlocalboundingbox       = DMGetLocalBoundingBox_Coordinates;
4815:   dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex;
4816:   dm->ops->createddscatters          = DMCreateDomainDecompositionScatters_Plex;
4817:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex));
4818:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex));
4819:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex));
4820:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex));
4821:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex));
4822:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex));
4823:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex));
4824:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex));
4825:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex));
4826:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex));
4827:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex));
4828:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex));
4829:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex));
4830:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex));
4831:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex));
4832:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex));
4833:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex));
4834:   PetscFunctionReturn(PETSC_SUCCESS);
4835: }

4837: PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
4838: {
4839:   DM_Plex       *mesh = (DM_Plex *)dm->data;
4840:   const PetscSF *face_sfs;
4841:   PetscInt       num_face_sfs;

4843:   PetscFunctionBegin;
4844:   mesh->refct++;
4845:   (*newdm)->data = mesh;
4846:   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs));
4847:   PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs));
4848:   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX));
4849:   PetscCall(DMInitialize_Plex(*newdm));
4850:   PetscFunctionReturn(PETSC_SUCCESS);
4851: }

4853: /*MC
4854:   DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram.
4855:                     In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is
4856:                     specified by a PetscSection object. Ownership in the global representation is determined by
4857:                     ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object.

4859:   Options Database Keys:
4860: + -dm_refine_pre                     - Refine mesh before distribution
4861: + -dm_refine_uniform_pre             - Choose uniform or generator-based refinement
4862: + -dm_refine_volume_limit_pre        - Cell volume limit after pre-refinement using generator
4863: . -dm_distribute                     - Distribute mesh across processes
4864: . -dm_distribute_overlap             - Number of cells to overlap for distribution
4865: . -dm_refine                         - Refine mesh after distribution
4866: . -dm_localize <bool>                - Whether to localize coordinates for periodic meshes
4867: . -dm_sparse_localize <bool>         - Whether to only localize cells on the periodic boundary
4868: . -dm_plex_hash_location             - Use grid hashing for point location
4869: . -dm_plex_hash_box_faces <n,m,p>    - The number of divisions in each direction of the grid hash
4870: . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
4871: . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
4872: . -dm_plex_max_projection_height     - Maximum mesh point height used to project locally
4873: . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
4874: . -dm_plex_reorder_section           - Use specialized blocking if available
4875: . -dm_plex_check_all                 - Perform all checks below
4876: . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
4877: . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
4878: . -dm_plex_check_faces <celltype>    - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
4879: . -dm_plex_check_geometry            - Check that cells have positive volume
4880: . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
4881: . -dm_plex_view_scale <num>          - Scale the TikZ
4882: . -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices
4883: - -dm_plex_print_fvm <num>           - View FVM assembly information, such as flux updates

4885:   Level: intermediate

4887: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection`
4888: M*/

4890: PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
4891: {
4892:   DM_Plex *mesh;
4893:   PetscInt unit;

4895:   PetscFunctionBegin;
4896:   PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite));
4898:   PetscCall(PetscNew(&mesh));
4899:   dm->reorderSection = DM_REORDER_DEFAULT_NOTSET;
4900:   dm->data           = mesh;

4902:   mesh->refct = 1;
4903:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection));
4904:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection));
4905:   mesh->refinementUniform      = PETSC_TRUE;
4906:   mesh->refinementLimit        = -1.0;
4907:   mesh->distDefault            = PETSC_TRUE;
4908:   mesh->reorderDefault         = DM_REORDER_DEFAULT_NOTSET;
4909:   mesh->distributionName       = NULL;
4910:   mesh->interpolated           = DMPLEX_INTERPOLATED_INVALID;
4911:   mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID;

4913:   PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner));
4914:   mesh->remeshBd = PETSC_FALSE;

4916:   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;

4918:   mesh->depthState    = -1;
4919:   mesh->celltypeState = -1;
4920:   mesh->printTol      = 1.0e-10;

4922:   PetscCall(DMInitialize_Plex(dm));
4923:   PetscFunctionReturn(PETSC_SUCCESS);
4924: }

4926: /*@
4927:   DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.

4929:   Collective

4931:   Input Parameter:
4932: . comm - The communicator for the `DMPLEX` object

4934:   Output Parameter:
4935: . mesh - The `DMPLEX` object

4937:   Level: beginner

4939: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()`
4940: @*/
4941: PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
4942: {
4943:   PetscFunctionBegin;
4944:   PetscAssertPointer(mesh, 2);
4945:   PetscCall(DMCreate(comm, mesh));
4946:   PetscCall(DMSetType(*mesh, DMPLEX));
4947:   PetscFunctionReturn(PETSC_SUCCESS);
4948: }

4950: /*@C
4951:   DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)

4953:   Collective; No Fortran Support

4955:   Input Parameters:
4956: + dm          - The `DM`
4957: . numCells    - The number of cells owned by this process
4958: . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
4959: . NVertices   - The global number of vertices, or `PETSC_DETERMINE`
4960: . numCorners  - The number of vertices for each cell
4961: - cells       - An array of numCells*numCorners numbers, the global vertex numbers for each cell

4963:   Output Parameters:
4964: + vertexSF         - (Optional) `PetscSF` describing complete vertex ownership
4965: - verticesAdjSaved - (Optional) vertex adjacency array

4967:   Level: advanced

4969:   Notes:
4970:   Two triangles sharing a face
4971: .vb

4973:         2
4974:       / | \
4975:      /  |  \
4976:     /   |   \
4977:    0  0 | 1  3
4978:     \   |   /
4979:      \  |  /
4980:       \ | /
4981:         1
4982: .ve
4983:   would have input
4984: .vb
4985:   numCells = 2, numVertices = 4
4986:   cells = [0 1 2  1 3 2]
4987: .ve
4988:   which would result in the `DMPLEX`
4989: .vb

4991:         4
4992:       / | \
4993:      /  |  \
4994:     /   |   \
4995:    2  0 | 1  5
4996:     \   |   /
4997:      \  |  /
4998:       \ | /
4999:         3
5000: .ve

5002:   Vertices are implicitly numbered consecutively 0,...,NVertices.
5003:   Each rank owns a chunk of numVertices consecutive vertices.
5004:   If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout.
5005:   If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1.
5006:   If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks.

5008:   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.

5010: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
5011:           `PetscSF`
5012: @*/
5013: PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved)
5014: {
5015:   PetscSF     sfPoint;
5016:   PetscLayout layout;
5017:   PetscInt    numVerticesAdj, *verticesAdj, *cones, c, p;

5019:   PetscFunctionBegin;
5021:   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5022:   /* Get/check global number of vertices */
5023:   {
5024:     PetscInt       NVerticesInCells, i;
5025:     const PetscInt len = numCells * numCorners;

5027:     /* NVerticesInCells = max(cells) + 1 */
5028:     NVerticesInCells = PETSC_MIN_INT;
5029:     for (i = 0; i < len; i++)
5030:       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
5031:     ++NVerticesInCells;
5032:     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));

5034:     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
5035:     else
5036:       PetscCheck(NVertices == PETSC_DECIDE || NVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, NVertices, NVerticesInCells);
5037:   }
5038:   /* Count locally unique vertices */
5039:   {
5040:     PetscHSetI vhash;
5041:     PetscInt   off = 0;

5043:     PetscCall(PetscHSetICreate(&vhash));
5044:     for (c = 0; c < numCells; ++c) {
5045:       for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p]));
5046:     }
5047:     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
5048:     if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
5049:     else verticesAdj = *verticesAdjSaved;
5050:     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
5051:     PetscCall(PetscHSetIDestroy(&vhash));
5052:     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
5053:   }
5054:   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
5055:   /* Create cones */
5056:   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
5057:   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
5058:   PetscCall(DMSetUp(dm));
5059:   PetscCall(DMPlexGetCones(dm, &cones));
5060:   for (c = 0; c < numCells; ++c) {
5061:     for (p = 0; p < numCorners; ++p) {
5062:       const PetscInt gv = cells[c * numCorners + p];
5063:       PetscInt       lv;

5065:       /* Positions within verticesAdj form 0-based local vertex numbering;
5066:          we need to shift it by numCells to get correct DAG points (cells go first) */
5067:       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
5068:       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
5069:       cones[c * numCorners + p] = lv + numCells;
5070:     }
5071:   }
5072:   /* Build point sf */
5073:   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
5074:   PetscCall(PetscLayoutSetSize(layout, NVertices));
5075:   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
5076:   PetscCall(PetscLayoutSetBlockSize(layout, 1));
5077:   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
5078:   PetscCall(PetscLayoutDestroy(&layout));
5079:   if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj));
5080:   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
5081:   if (dm->sf) {
5082:     const char *prefix;

5084:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
5085:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
5086:   }
5087:   PetscCall(DMSetPointSF(dm, sfPoint));
5088:   PetscCall(PetscSFDestroy(&sfPoint));
5089:   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF"));
5090:   /* Fill in the rest of the topology structure */
5091:   PetscCall(DMPlexSymmetrize(dm));
5092:   PetscCall(DMPlexStratify(dm));
5093:   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5094:   PetscFunctionReturn(PETSC_SUCCESS);
5095: }

5097: /*@C
5098:   DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)

5100:   Collective; No Fortran Support

5102:   Input Parameters:
5103: + dm           - The `DM`
5104: . spaceDim     - The spatial dimension used for coordinates
5105: . sfVert       - `PetscSF` describing complete vertex ownership
5106: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex

5108:   Level: advanced

5110: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()`
5111: @*/
5112: PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[])
5113: {
5114:   PetscSection coordSection;
5115:   Vec          coordinates;
5116:   PetscScalar *coords;
5117:   PetscInt     numVertices, numVerticesAdj, coordSize, v, vStart, vEnd;

5119:   PetscFunctionBegin;
5120:   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5121:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5122:   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
5123:   PetscCall(DMSetCoordinateDim(dm, spaceDim));
5124:   PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL));
5125:   PetscCheck(vEnd - vStart == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Supplied sfVert has wrong number of leaves = %" PetscInt_FMT " != %" PetscInt_FMT " = vEnd - vStart", numVerticesAdj, vEnd - vStart);
5126:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5127:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5128:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
5129:   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
5130:   for (v = vStart; v < vEnd; ++v) {
5131:     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
5132:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
5133:   }
5134:   PetscCall(PetscSectionSetUp(coordSection));
5135:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5136:   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates));
5137:   PetscCall(VecSetBlockSize(coordinates, spaceDim));
5138:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5139:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5140:   PetscCall(VecSetType(coordinates, VECSTANDARD));
5141:   PetscCall(VecGetArray(coordinates, &coords));
5142:   {
5143:     MPI_Datatype coordtype;

5145:     /* Need a temp buffer for coords if we have complex/single */
5146:     PetscCallMPI(MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype));
5147:     PetscCallMPI(MPI_Type_commit(&coordtype));
5148: #if defined(PETSC_USE_COMPLEX)
5149:     {
5150:       PetscScalar *svertexCoords;
5151:       PetscInt     i;
5152:       PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords));
5153:       for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i];
5154:       PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
5155:       PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
5156:       PetscCall(PetscFree(svertexCoords));
5157:     }
5158: #else
5159:     PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
5160:     PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
5161: #endif
5162:     PetscCallMPI(MPI_Type_free(&coordtype));
5163:   }
5164:   PetscCall(VecRestoreArray(coordinates, &coords));
5165:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5166:   PetscCall(VecDestroy(&coordinates));
5167:   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5168:   PetscFunctionReturn(PETSC_SUCCESS);
5169: }

5171: /*@
5172:   DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output)

5174:   Collective

5176:   Input Parameters:
5177: + comm         - The communicator
5178: . dim          - The topological dimension of the mesh
5179: . numCells     - The number of cells owned by this process
5180: . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`
5181: . NVertices    - The global number of vertices, or `PETSC_DECIDE`
5182: . numCorners   - The number of vertices for each cell
5183: . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
5184: . cells        - An array of numCells*numCorners numbers, the global vertex numbers for each cell
5185: . spaceDim     - The spatial dimension used for coordinates
5186: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex

5188:   Output Parameters:
5189: + dm          - The `DM`
5190: . vertexSF    - (Optional) `PetscSF` describing complete vertex ownership
5191: - verticesAdj - (Optional) vertex adjacency array

5193:   Level: intermediate

5195:   Notes:
5196:   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
5197:   `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`

5199:   See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters.

5201:   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.

5203: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
5204: @*/
5205: PetscErrorCode DMPlexCreateFromCellListParallelPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PetscSF *vertexSF, PetscInt **verticesAdj, DM *dm)
5206: {
5207:   PetscSF sfVert;

5209:   PetscFunctionBegin;
5210:   PetscCall(DMCreate(comm, dm));
5211:   PetscCall(DMSetType(*dm, DMPLEX));
5214:   PetscCall(DMSetDimension(*dm, dim));
5215:   PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj));
5216:   if (interpolate) {
5217:     DM idm;

5219:     PetscCall(DMPlexInterpolate(*dm, &idm));
5220:     PetscCall(DMDestroy(dm));
5221:     *dm = idm;
5222:   }
5223:   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
5224:   if (vertexSF) *vertexSF = sfVert;
5225:   else PetscCall(PetscSFDestroy(&sfVert));
5226:   PetscFunctionReturn(PETSC_SUCCESS);
5227: }

5229: /*@C
5230:   DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)

5232:   Collective; No Fortran Support

5234:   Input Parameters:
5235: + dm          - The `DM`
5236: . numCells    - The number of cells owned by this process
5237: . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE`
5238: . numCorners  - The number of vertices for each cell
5239: - cells       - An array of numCells*numCorners numbers, the global vertex numbers for each cell

5241:   Level: advanced

5243:   Notes:
5244:   Two triangles sharing a face
5245: .vb

5247:         2
5248:       / | \
5249:      /  |  \
5250:     /   |   \
5251:    0  0 | 1  3
5252:     \   |   /
5253:      \  |  /
5254:       \ | /
5255:         1
5256: .ve
5257:   would have input
5258: .vb
5259:   numCells = 2, numVertices = 4
5260:   cells = [0 1 2  1 3 2]
5261: .ve
5262:   which would result in the `DMPLEX`
5263: .vb

5265:         4
5266:       / | \
5267:      /  |  \
5268:     /   |   \
5269:    2  0 | 1  5
5270:     \   |   /
5271:      \  |  /
5272:       \ | /
5273:         3
5274: .ve

5276:   If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1.

5278: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()`
5279: @*/
5280: PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[])
5281: {
5282:   PetscInt *cones, c, p, dim;

5284:   PetscFunctionBegin;
5285:   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5286:   PetscCall(DMGetDimension(dm, &dim));
5287:   /* Get/check global number of vertices */
5288:   {
5289:     PetscInt       NVerticesInCells, i;
5290:     const PetscInt len = numCells * numCorners;

5292:     /* NVerticesInCells = max(cells) + 1 */
5293:     NVerticesInCells = PETSC_MIN_INT;
5294:     for (i = 0; i < len; i++)
5295:       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
5296:     ++NVerticesInCells;

5298:     if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells;
5299:     else
5300:       PetscCheck(numVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, numVertices, NVerticesInCells);
5301:   }
5302:   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
5303:   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
5304:   PetscCall(DMSetUp(dm));
5305:   PetscCall(DMPlexGetCones(dm, &cones));
5306:   for (c = 0; c < numCells; ++c) {
5307:     for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells;
5308:   }
5309:   PetscCall(DMPlexSymmetrize(dm));
5310:   PetscCall(DMPlexStratify(dm));
5311:   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5312:   PetscFunctionReturn(PETSC_SUCCESS);
5313: }

5315: /*@C
5316:   DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)

5318:   Collective; No Fortran Support

5320:   Input Parameters:
5321: + dm           - The `DM`
5322: . spaceDim     - The spatial dimension used for coordinates
5323: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex

5325:   Level: advanced

5327: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()`
5328: @*/
5329: PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[])
5330: {
5331:   PetscSection coordSection;
5332:   Vec          coordinates;
5333:   DM           cdm;
5334:   PetscScalar *coords;
5335:   PetscInt     v, vStart, vEnd, d;

5337:   PetscFunctionBegin;
5338:   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5339:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5340:   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
5341:   PetscCall(DMSetCoordinateDim(dm, spaceDim));
5342:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5343:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5344:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
5345:   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
5346:   for (v = vStart; v < vEnd; ++v) {
5347:     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
5348:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
5349:   }
5350:   PetscCall(PetscSectionSetUp(coordSection));

5352:   PetscCall(DMGetCoordinateDM(dm, &cdm));
5353:   PetscCall(DMCreateLocalVector(cdm, &coordinates));
5354:   PetscCall(VecSetBlockSize(coordinates, spaceDim));
5355:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5356:   PetscCall(VecGetArrayWrite(coordinates, &coords));
5357:   for (v = 0; v < vEnd - vStart; ++v) {
5358:     for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d];
5359:   }
5360:   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5361:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5362:   PetscCall(VecDestroy(&coordinates));
5363:   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5364:   PetscFunctionReturn(PETSC_SUCCESS);
5365: }

5367: /*@
5368:   DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input

5370:   Collective

5372:   Input Parameters:
5373: + comm         - The communicator
5374: . dim          - The topological dimension of the mesh
5375: . numCells     - The number of cells, only on process 0
5376: . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0
5377: . numCorners   - The number of vertices for each cell, only on process 0
5378: . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
5379: . cells        - An array of numCells*numCorners numbers, the vertices for each cell, only on process 0
5380: . spaceDim     - The spatial dimension used for coordinates
5381: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex, only on process 0

5383:   Output Parameter:
5384: . dm - The `DM`, which only has points on process 0

5386:   Level: intermediate

5388:   Notes:
5389:   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`,
5390:   `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()`

5392:   See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters.
5393:   See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters.
5394:   See `DMPlexCreateFromCellListParallelPetsc()` for parallel input

5396: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
5397: @*/
5398: PetscErrorCode DMPlexCreateFromCellListPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], DM *dm)
5399: {
5400:   PetscMPIInt rank;

5402:   PetscFunctionBegin;
5403:   PetscCheck(dim, comm, PETSC_ERR_ARG_OUTOFRANGE, "This is not appropriate for 0-dimensional meshes. Consider either creating the DM using DMPlexCreateFromDAG(), by hand, or using DMSwarm.");
5404:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5405:   PetscCall(DMCreate(comm, dm));
5406:   PetscCall(DMSetType(*dm, DMPLEX));
5407:   PetscCall(DMSetDimension(*dm, dim));
5408:   if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells));
5409:   else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL));
5410:   if (interpolate) {
5411:     DM idm;

5413:     PetscCall(DMPlexInterpolate(*dm, &idm));
5414:     PetscCall(DMDestroy(dm));
5415:     *dm = idm;
5416:   }
5417:   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords));
5418:   else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL));
5419:   PetscFunctionReturn(PETSC_SUCCESS);
5420: }

5422: /*@
5423:   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM`

5425:   Input Parameters:
5426: + dm               - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()`
5427: . depth            - The depth of the DAG
5428: . numPoints        - Array of size depth + 1 containing the number of points at each `depth`
5429: . coneSize         - The cone size of each point
5430: . cones            - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
5431: . coneOrientations - The orientation of each cone point
5432: - vertexCoords     - An array of `numPoints`[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via `DMSetCoordinateDim()`

5434:   Output Parameter:
5435: . dm - The `DM`

5437:   Level: advanced

5439:   Note:
5440:   Two triangles sharing a face would have input
5441: .vb
5442:   depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
5443:   cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
5444:  vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
5445: .ve
5446:   which would result in the DMPlex
5447: .vb
5448:         4
5449:       / | \
5450:      /  |  \
5451:     /   |   \
5452:    2  0 | 1  5
5453:     \   |   /
5454:      \  |  /
5455:       \ | /
5456:         3
5457: .ve
5458:   Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()`

5460: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
5461: @*/
5462: PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
5463: {
5464:   Vec          coordinates;
5465:   PetscSection coordSection;
5466:   PetscScalar *coords;
5467:   PetscInt     coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;

5469:   PetscFunctionBegin;
5470:   PetscCall(DMGetDimension(dm, &dim));
5471:   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
5472:   PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim);
5473:   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
5474:   PetscCall(DMPlexSetChart(dm, pStart, pEnd));
5475:   for (p = pStart; p < pEnd; ++p) {
5476:     PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart]));
5477:     if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart;
5478:   }
5479:   PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]);
5480:   PetscCall(DMSetUp(dm)); /* Allocate space for cones */
5481:   for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) {
5482:     PetscCall(DMPlexSetCone(dm, p, &cones[off]));
5483:     PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off]));
5484:   }
5485:   PetscCall(DMPlexSymmetrize(dm));
5486:   PetscCall(DMPlexStratify(dm));
5487:   /* Build coordinates */
5488:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5489:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5490:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed));
5491:   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0]));
5492:   for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) {
5493:     PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed));
5494:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed));
5495:   }
5496:   PetscCall(PetscSectionSetUp(coordSection));
5497:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5498:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5499:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5500:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5501:   PetscCall(VecSetBlockSize(coordinates, dimEmbed));
5502:   PetscCall(VecSetType(coordinates, VECSTANDARD));
5503:   if (vertexCoords) {
5504:     PetscCall(VecGetArray(coordinates, &coords));
5505:     for (v = 0; v < numPoints[0]; ++v) {
5506:       PetscInt off;

5508:       PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off));
5509:       for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d];
5510:     }
5511:   }
5512:   PetscCall(VecRestoreArray(coordinates, &coords));
5513:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5514:   PetscCall(VecDestroy(&coordinates));
5515:   PetscFunctionReturn(PETSC_SUCCESS);
5516: }

5518: /*
5519:   DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file.

5521:   Collective

5523: + comm        - The MPI communicator
5524: . filename    - Name of the .dat file
5525: - interpolate - Create faces and edges in the mesh

5527:   Output Parameter:
5528: . dm  - The `DM` object representing the mesh

5530:   Level: beginner

5532:   Note:
5533:   The format is the simplest possible:
5534: .vb
5535:   dim Ne Nv Nc Nl
5536:   v_1 v_2 ... v_Nc
5537:   ...
5538:   x y z marker_1 ... marker_Nl
5539: .ve

5541:   Developer Note:
5542:   Should use a `PetscViewer` not a filename

5544: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
5545: */
5546: static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
5547: {
5548:   DMLabel      marker;
5549:   PetscViewer  viewer;
5550:   Vec          coordinates;
5551:   PetscSection coordSection;
5552:   PetscScalar *coords;
5553:   char         line[PETSC_MAX_PATH_LEN];
5554:   PetscInt     cdim, coordSize, v, c, d;
5555:   PetscMPIInt  rank;
5556:   int          snum, dim, Nv, Nc, Ncn, Nl;

5558:   PetscFunctionBegin;
5559:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5560:   PetscCall(PetscViewerCreate(comm, &viewer));
5561:   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
5562:   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
5563:   PetscCall(PetscViewerFileSetName(viewer, filename));
5564:   if (rank == 0) {
5565:     PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING));
5566:     snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl);
5567:     PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5568:   } else {
5569:     Nc = Nv = Ncn = Nl = 0;
5570:   }
5571:   PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
5572:   cdim = (PetscInt)dim;
5573:   PetscCall(DMCreate(comm, dm));
5574:   PetscCall(DMSetType(*dm, DMPLEX));
5575:   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
5576:   PetscCall(DMSetDimension(*dm, (PetscInt)dim));
5577:   PetscCall(DMSetCoordinateDim(*dm, cdim));
5578:   /* Read topology */
5579:   if (rank == 0) {
5580:     char     format[PETSC_MAX_PATH_LEN];
5581:     PetscInt cone[8];
5582:     int      vbuf[8], v;

5584:     for (c = 0; c < Ncn; ++c) {
5585:       format[c * 3 + 0] = '%';
5586:       format[c * 3 + 1] = 'd';
5587:       format[c * 3 + 2] = ' ';
5588:     }
5589:     format[Ncn * 3 - 1] = '\0';
5590:     for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn));
5591:     PetscCall(DMSetUp(*dm));
5592:     for (c = 0; c < Nc; ++c) {
5593:       PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING));
5594:       switch (Ncn) {
5595:       case 2:
5596:         snum = sscanf(line, format, &vbuf[0], &vbuf[1]);
5597:         break;
5598:       case 3:
5599:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]);
5600:         break;
5601:       case 4:
5602:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]);
5603:         break;
5604:       case 6:
5605:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]);
5606:         break;
5607:       case 8:
5608:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]);
5609:         break;
5610:       default:
5611:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn);
5612:       }
5613:       PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5614:       for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc;
5615:       /* Hexahedra are inverted */
5616:       if (Ncn == 8) {
5617:         PetscInt tmp = cone[1];
5618:         cone[1]      = cone[3];
5619:         cone[3]      = tmp;
5620:       }
5621:       PetscCall(DMPlexSetCone(*dm, c, cone));
5622:     }
5623:   }
5624:   PetscCall(DMPlexSymmetrize(*dm));
5625:   PetscCall(DMPlexStratify(*dm));
5626:   /* Read coordinates */
5627:   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
5628:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5629:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
5630:   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
5631:   for (v = Nc; v < Nc + Nv; ++v) {
5632:     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
5633:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
5634:   }
5635:   PetscCall(PetscSectionSetUp(coordSection));
5636:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5637:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5638:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5639:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5640:   PetscCall(VecSetBlockSize(coordinates, cdim));
5641:   PetscCall(VecSetType(coordinates, VECSTANDARD));
5642:   PetscCall(VecGetArray(coordinates, &coords));
5643:   if (rank == 0) {
5644:     char   format[PETSC_MAX_PATH_LEN];
5645:     double x[3];
5646:     int    l, val[3];

5648:     if (Nl) {
5649:       for (l = 0; l < Nl; ++l) {
5650:         format[l * 3 + 0] = '%';
5651:         format[l * 3 + 1] = 'd';
5652:         format[l * 3 + 2] = ' ';
5653:       }
5654:       format[Nl * 3 - 1] = '\0';
5655:       PetscCall(DMCreateLabel(*dm, "marker"));
5656:       PetscCall(DMGetLabel(*dm, "marker", &marker));
5657:     }
5658:     for (v = 0; v < Nv; ++v) {
5659:       PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING));
5660:       snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]);
5661:       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5662:       switch (Nl) {
5663:       case 0:
5664:         snum = 0;
5665:         break;
5666:       case 1:
5667:         snum = sscanf(line, format, &val[0]);
5668:         break;
5669:       case 2:
5670:         snum = sscanf(line, format, &val[0], &val[1]);
5671:         break;
5672:       case 3:
5673:         snum = sscanf(line, format, &val[0], &val[1], &val[2]);
5674:         break;
5675:       default:
5676:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl);
5677:       }
5678:       PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5679:       for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d];
5680:       for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l]));
5681:     }
5682:   }
5683:   PetscCall(VecRestoreArray(coordinates, &coords));
5684:   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
5685:   PetscCall(VecDestroy(&coordinates));
5686:   PetscCall(PetscViewerDestroy(&viewer));
5687:   if (interpolate) {
5688:     DM      idm;
5689:     DMLabel bdlabel;

5691:     PetscCall(DMPlexInterpolate(*dm, &idm));
5692:     PetscCall(DMDestroy(dm));
5693:     *dm = idm;

5695:     if (!Nl) {
5696:       PetscCall(DMCreateLabel(*dm, "marker"));
5697:       PetscCall(DMGetLabel(*dm, "marker", &bdlabel));
5698:       PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel));
5699:       PetscCall(DMPlexLabelComplete(*dm, bdlabel));
5700:     }
5701:   }
5702:   PetscFunctionReturn(PETSC_SUCCESS);
5703: }

5705: /*@C
5706:   DMPlexCreateFromFile - This takes a filename and produces a `DM`

5708:   Collective

5710:   Input Parameters:
5711: + comm        - The communicator
5712: . filename    - A file name
5713: . plexname    - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats
5714: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

5716:   Output Parameter:
5717: . dm - The `DM`

5719:   Options Database Key:
5720: . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5

5722:   Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g.
5723: $ -dm_plex_create_viewer_hdf5_collective

5725:   Level: beginner

5727:   Notes:
5728:   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
5729:   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
5730:   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
5731:   The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally
5732:   calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats.

5734: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()`
5735: @*/
5736: PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm)
5737: {
5738:   const char  extGmsh[]      = ".msh";
5739:   const char  extGmsh2[]     = ".msh2";
5740:   const char  extGmsh4[]     = ".msh4";
5741:   const char  extCGNS[]      = ".cgns";
5742:   const char  extExodus[]    = ".exo";
5743:   const char  extExodus_e[]  = ".e";
5744:   const char  extGenesis[]   = ".gen";
5745:   const char  extFluent[]    = ".cas";
5746:   const char  extHDF5[]      = ".h5";
5747:   const char  extXDMFHDF5[]  = ".xdmf.h5";
5748:   const char  extPLY[]       = ".ply";
5749:   const char  extEGADSLite[] = ".egadslite";
5750:   const char  extEGADS[]     = ".egads";
5751:   const char  extIGES[]      = ".igs";
5752:   const char  extSTEP[]      = ".stp";
5753:   const char  extCV[]        = ".dat";
5754:   size_t      len;
5755:   PetscBool   isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSLite, isEGADS, isIGES, isSTEP, isCV, isXDMFHDF5;
5756:   PetscMPIInt rank;

5758:   PetscFunctionBegin;
5759:   PetscAssertPointer(filename, 2);
5760:   if (plexname) PetscAssertPointer(plexname, 3);
5761:   PetscAssertPointer(dm, 5);
5762:   PetscCall(DMInitializePackage());
5763:   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0));
5764:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5765:   PetscCall(PetscStrlen(filename, &len));
5766:   PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");

5768: #define CheckExtension(extension__, is_extension__) \
5769:   do { \
5770:     PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \
5771:     /* don't count the null-terminator at the end */ \
5772:     const size_t ext_len = sizeof(extension__) - 1; \
5773:     if (len < ext_len) { \
5774:       is_extension__ = PETSC_FALSE; \
5775:     } else { \
5776:       PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \
5777:     } \
5778:   } while (0)

5780:   CheckExtension(extGmsh, isGmsh);
5781:   CheckExtension(extGmsh2, isGmsh2);
5782:   CheckExtension(extGmsh4, isGmsh4);
5783:   CheckExtension(extCGNS, isCGNS);
5784:   CheckExtension(extExodus, isExodus);
5785:   if (!isExodus) CheckExtension(extExodus_e, isExodus);
5786:   CheckExtension(extGenesis, isGenesis);
5787:   CheckExtension(extFluent, isFluent);
5788:   CheckExtension(extHDF5, isHDF5);
5789:   CheckExtension(extPLY, isPLY);
5790:   CheckExtension(extEGADSLite, isEGADSLite);
5791:   CheckExtension(extEGADS, isEGADS);
5792:   CheckExtension(extIGES, isIGES);
5793:   CheckExtension(extSTEP, isSTEP);
5794:   CheckExtension(extCV, isCV);
5795:   CheckExtension(extXDMFHDF5, isXDMFHDF5);

5797: #undef CheckExtension

5799:   if (isGmsh || isGmsh2 || isGmsh4) {
5800:     PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm));
5801:   } else if (isCGNS) {
5802:     PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm));
5803:   } else if (isExodus || isGenesis) {
5804:     PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm));
5805:   } else if (isFluent) {
5806:     PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm));
5807:   } else if (isHDF5) {
5808:     PetscViewer viewer;

5810:     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
5811:     PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL));
5812:     PetscCall(PetscViewerCreate(comm, &viewer));
5813:     PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5));
5814:     PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_"));
5815:     PetscCall(PetscViewerSetFromOptions(viewer));
5816:     PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
5817:     PetscCall(PetscViewerFileSetName(viewer, filename));

5819:     PetscCall(DMCreate(comm, dm));
5820:     PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
5821:     PetscCall(DMSetType(*dm, DMPLEX));
5822:     if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF));
5823:     PetscCall(DMLoad(*dm, viewer));
5824:     if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer));
5825:     PetscCall(PetscViewerDestroy(&viewer));

5827:     if (interpolate) {
5828:       DM idm;

5830:       PetscCall(DMPlexInterpolate(*dm, &idm));
5831:       PetscCall(DMDestroy(dm));
5832:       *dm = idm;
5833:     }
5834:   } else if (isPLY) {
5835:     PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm));
5836:   } else if (isEGADSLite || isEGADS || isIGES || isSTEP) {
5837:     if (isEGADSLite) PetscCall(DMPlexCreateEGADSLiteFromFile(comm, filename, dm));
5838:     else PetscCall(DMPlexCreateEGADSFromFile(comm, filename, dm));
5839:     if (!interpolate) {
5840:       DM udm;

5842:       PetscCall(DMPlexUninterpolate(*dm, &udm));
5843:       PetscCall(DMDestroy(dm));
5844:       *dm = udm;
5845:     }
5846:   } else if (isCV) {
5847:     PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm));
5848:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
5849:   PetscCall(PetscStrlen(plexname, &len));
5850:   if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
5851:   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0));
5852:   PetscFunctionReturn(PETSC_SUCCESS);
5853: }

5855: /*@C
5856:   DMPlexCreateEphemeral - This takes a `DMPlexTransform` and a base `DMPlex` and produces an ephemeral `DM`, meaning one that is created on the fly in response to queries.

5858:   Input Parameters:
5859: + tr     - The `DMPlexTransform`
5860: - prefix - An options prefix, or NULL

5862:   Output Parameter:
5863: . dm - The `DM`

5865:   Level: beginner

5867:   Notes:
5868:   An emphemeral mesh is one that is not stored concretely, as in the default `DMPLEX` implementation, but rather is produced on the fly in response to queries, using information from the transform and the base mesh.

5870: .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
5871: @*/
5872: PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm)
5873: {
5874:   DM           bdm, bcdm, cdm;
5875:   Vec          coordinates, coordinatesNew;
5876:   PetscSection cs;
5877:   PetscInt     dim, cdim, Nl;

5879:   PetscFunctionBegin;
5880:   PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm));
5881:   PetscCall(DMSetType(*dm, DMPLEX));
5882:   ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL;
5883:   // Handle coordinates
5884:   PetscCall(DMPlexTransformGetDM(tr, &bdm));
5885:   PetscCall(DMGetCoordinateDim(bdm, &cdim));
5886:   PetscCall(DMSetCoordinateDim(*dm, cdim));
5887:   PetscCall(DMGetDimension(bdm, &dim));
5888:   PetscCall(DMSetDimension(*dm, dim));
5889:   PetscCall(DMGetCoordinateDM(bdm, &bcdm));
5890:   PetscCall(DMGetCoordinateDM(*dm, &cdm));
5891:   PetscCall(DMCopyDisc(bcdm, cdm));
5892:   PetscCall(DMGetLocalSection(cdm, &cs));
5893:   PetscCall(PetscSectionSetNumFields(cs, 1));
5894:   PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim));
5895:   PetscCall(DMGetCoordinatesLocal(bdm, &coordinates));
5896:   PetscCall(VecDuplicate(coordinates, &coordinatesNew));
5897:   PetscCall(VecCopy(coordinates, coordinatesNew));
5898:   PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew));
5899:   PetscCall(VecDestroy(&coordinatesNew));

5901:   PetscCall(PetscObjectReference((PetscObject)tr));
5902:   PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr));
5903:   ((DM_Plex *)(*dm)->data)->tr = tr;
5904:   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
5905:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix));
5906:   PetscCall(DMSetFromOptions(*dm));

5908:   PetscCall(DMGetNumLabels(bdm, &Nl));
5909:   for (PetscInt l = 0; l < Nl; ++l) {
5910:     DMLabel     label, labelNew;
5911:     const char *lname;
5912:     PetscBool   isDepth, isCellType;

5914:     PetscCall(DMGetLabelName(bdm, l, &lname));
5915:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
5916:     if (isDepth) continue;
5917:     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
5918:     if (isCellType) continue;
5919:     PetscCall(DMCreateLabel(*dm, lname));
5920:     PetscCall(DMGetLabel(bdm, lname, &label));
5921:     PetscCall(DMGetLabel(*dm, lname, &labelNew));
5922:     PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL));
5923:     PetscCall(DMLabelEphemeralSetLabel(labelNew, label));
5924:     PetscCall(DMLabelEphemeralSetTransform(labelNew, tr));
5925:     PetscCall(DMLabelSetUp(labelNew));
5926:   }
5927:   PetscFunctionReturn(PETSC_SUCCESS);
5928: }