xref: /petsc/src/dm/impls/plex/plexcreate.c (revision d9126033840fa4b9e125cadad06c85976e6bf099) !
1 #include <petsc/private/dmpleximpl.h> /*I   "petscdmplex.h"   I*/
2 #include <petsc/private/hashseti.h>
3 #include <petscsf.h>
4 #include <petscdmplextransform.h> /*I   "petscdmplextransform.h"   I*/
5 #include <petscdmlabelephemeral.h>
6 #include <petsc/private/kernels/blockmatmult.h>
7 #include <petsc/private/kernels/blockinvert.h>
8 
9 #ifdef PETSC_HAVE_UNISTD_H
10   #include <unistd.h>
11 #endif
12 #include <errno.h>
13 
14 PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_CreateFromOptions, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList;
15 
16 /* External function declarations here */
17 static PetscErrorCode DMInitialize_Plex(DM dm);
18 
DMPlexCheckEGADS_Private(DM dm)19 PETSC_EXTERN PetscErrorCode DMPlexCheckEGADS_Private(DM dm)
20 {
21   PetscObject modelObj;
22 
23   PetscFunctionBegin;
24   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", &modelObj));
25   PetscCheck(modelObj, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input DM must have attached EGADS Geometry Model");
26   PetscFunctionReturn(PETSC_SUCCESS);
27 }
28 
DMPlexCopyContext_Private(DM dmin,const char name[],DM dmout)29 static PetscErrorCode DMPlexCopyContext_Private(DM dmin, const char name[], DM dmout)
30 {
31   PetscObject obj;
32 
33   PetscFunctionBegin;
34   PetscCall(PetscObjectQuery((PetscObject)dmin, name, &obj));
35   if (obj) PetscCall(PetscObjectCompose((PetscObject)dmout, name, obj));
36   PetscFunctionReturn(PETSC_SUCCESS);
37 }
38 
DMPlexSwapContext_Private(DM dmA,const char name[],DM dmB)39 static PetscErrorCode DMPlexSwapContext_Private(DM dmA, const char name[], DM dmB)
40 {
41   PetscObject objA, objB;
42 
43   PetscFunctionBegin;
44   PetscCall(PetscObjectQuery((PetscObject)dmA, name, &objA));
45   PetscCall(PetscObjectQuery((PetscObject)dmB, name, &objB));
46   PetscCall(PetscObjectReference(objA));
47   PetscCall(PetscObjectReference(objB));
48   PetscCall(PetscObjectCompose((PetscObject)dmA, name, objB));
49   PetscCall(PetscObjectCompose((PetscObject)dmB, name, objA));
50   PetscCall(PetscObjectDereference(objA));
51   PetscCall(PetscObjectDereference(objB));
52   PetscFunctionReturn(PETSC_SUCCESS);
53 }
54 
DMPlexCopyEGADSInfo_Internal(DM dmin,DM dmout)55 PetscErrorCode DMPlexCopyEGADSInfo_Internal(DM dmin, DM dmout)
56 {
57   PetscFunctionBegin;
58   PetscCall(DMPlexCopyContext_Private(dmin, "EGADS Model", dmout));
59   PetscCall(DMPlexCopyContext_Private(dmin, "EGADS Context", dmout));
60   PetscCall(DMPlexCopyContext_Private(dmin, "EGADSlite Model", dmout));
61   PetscCall(DMPlexCopyContext_Private(dmin, "EGADSlite Context", dmout));
62   PetscFunctionReturn(PETSC_SUCCESS);
63 }
64 
DMPlexSwapEGADSInfo_Private(DM dmA,DM dmB)65 static PetscErrorCode DMPlexSwapEGADSInfo_Private(DM dmA, DM dmB)
66 {
67   PetscFunctionBegin;
68   PetscCall(DMPlexSwapContext_Private(dmA, "EGADS Model", dmB));
69   PetscCall(DMPlexSwapContext_Private(dmA, "EGADS Context", dmB));
70   PetscCall(DMPlexSwapContext_Private(dmA, "EGADSlite Model", dmB));
71   PetscCall(DMPlexSwapContext_Private(dmA, "EGADSlite Context", dmB));
72   PetscFunctionReturn(PETSC_SUCCESS);
73 }
74 
75 /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */
DMPlexCopy_Internal(DM dmin,PetscBool copyPeriodicity,PetscBool copyOverlap,DM dmout)76 PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout)
77 {
78   const PetscReal     *maxCell, *Lstart, *L;
79   VecType              vecType;
80   MatType              matType;
81   PetscBool            dist, useCeed, balance_partition;
82   DMReorderDefaultFlag reorder;
83 
84   PetscFunctionBegin;
85   if (dmin == dmout) PetscFunctionReturn(PETSC_SUCCESS);
86   PetscCall(DMGetVecType(dmin, &vecType));
87   PetscCall(DMSetVecType(dmout, vecType));
88   PetscCall(DMGetMatType(dmin, &matType));
89   PetscCall(DMSetMatType(dmout, matType));
90   if (copyPeriodicity) {
91     PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L));
92     PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L));
93     PetscCall(DMLocalizeCoordinates(dmout));
94   }
95   PetscCall(DMPlexDistributeGetDefault(dmin, &dist));
96   PetscCall(DMPlexDistributeSetDefault(dmout, dist));
97   PetscCall(DMPlexReorderGetDefault(dmin, &reorder));
98   PetscCall(DMPlexReorderSetDefault(dmout, reorder));
99   PetscCall(DMPlexGetUseCeed(dmin, &useCeed));
100   PetscCall(DMPlexSetUseCeed(dmout, useCeed));
101   PetscCall(DMPlexGetPartitionBalance(dmin, &balance_partition));
102   PetscCall(DMPlexSetPartitionBalance(dmout, balance_partition));
103   ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation;
104   ((DM_Plex *)dmout->data)->printSetValues  = ((DM_Plex *)dmin->data)->printSetValues;
105   ((DM_Plex *)dmout->data)->printFEM        = ((DM_Plex *)dmin->data)->printFEM;
106   ((DM_Plex *)dmout->data)->printFVM        = ((DM_Plex *)dmin->data)->printFVM;
107   ((DM_Plex *)dmout->data)->printL2         = ((DM_Plex *)dmin->data)->printL2;
108   ((DM_Plex *)dmout->data)->printLocate     = ((DM_Plex *)dmin->data)->printLocate;
109   ((DM_Plex *)dmout->data)->printProject    = ((DM_Plex *)dmin->data)->printProject;
110   ((DM_Plex *)dmout->data)->printTol        = ((DM_Plex *)dmin->data)->printTol;
111   if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0));
112   PetscCall(DMPlexCopyEGADSInfo_Internal(dmin, dmout));
113   PetscFunctionReturn(PETSC_SUCCESS);
114 }
115 
116 /* Replace dm with the contents of ndm, and then destroy ndm
117    - Share the DM_Plex structure
118    - Share the coordinates
119    - Share the SF
120 */
DMPlexReplace_Internal(DM dm,DM * ndm)121 PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm)
122 {
123   PetscSF          sf;
124   DM               dmNew = *ndm, coordDM, coarseDM;
125   Vec              coords;
126   PetscPointFn    *coordFunc;
127   const PetscReal *maxCell, *Lstart, *L;
128   PetscInt         dim, cdim;
129   PetscBool        use_natural;
130 
131   PetscFunctionBegin;
132   if (dm == dmNew) {
133     PetscCall(DMDestroy(ndm));
134     PetscFunctionReturn(PETSC_SUCCESS);
135   }
136   dm->setupcalled = dmNew->setupcalled;
137   if (!dm->hdr.name) {
138     const char *name;
139 
140     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
141     PetscCall(PetscObjectSetName((PetscObject)dm, name));
142   }
143   {
144     PetscInt ndim;
145 
146     // If topological dimensions are the same, we retain the old coordinate map,
147     //   otherwise we overwrite with the new one
148     PetscCall(DMGetDimension(dm, &dim));
149     PetscCall(DMGetDimension(dmNew, &ndim));
150     PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
151     if (dim == ndim) PetscCall(DMPlexSetCoordinateMap(dmNew, coordFunc));
152   }
153   PetscCall(DMGetDimension(dmNew, &dim));
154   PetscCall(DMSetDimension(dm, dim));
155   PetscCall(DMGetCoordinateDim(dmNew, &cdim));
156   PetscCall(DMSetCoordinateDim(dm, cdim));
157   PetscCall(DMGetPointSF(dmNew, &sf));
158   PetscCall(DMSetPointSF(dm, sf));
159   PetscCall(DMGetCoordinateDM(dmNew, &coordDM));
160   PetscCall(DMGetCoordinatesLocal(dmNew, &coords));
161   PetscCall(DMSetCoordinateDM(dm, coordDM));
162   PetscCall(DMSetCoordinatesLocal(dm, coords));
163   PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM));
164   PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords));
165   PetscCall(DMSetCellCoordinateDM(dm, coordDM));
166   PetscCall(DMSetCellCoordinatesLocal(dm, coords));
167   /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */
168   PetscCall(DMFieldDestroy(&dm->coordinates[0].field));
169   dm->coordinates[0].field = dmNew->coordinates[0].field;
170   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
171   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
172   PetscCall(DMGetNaturalSF(dmNew, &sf));
173   PetscCall(DMSetNaturalSF(dm, sf));
174   PetscCall(DMGetUseNatural(dmNew, &use_natural));
175   PetscCall(DMSetUseNatural(dm, use_natural));
176   PetscCall(DMDestroy_Plex(dm));
177   PetscCall(DMInitialize_Plex(dm));
178   dm->data = dmNew->data;
179   ((DM_Plex *)dmNew->data)->refct++;
180   {
181     PetscInt       num_face_sfs;
182     const PetscSF *sfs;
183     PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &sfs));
184     PetscCall(DMPlexSetIsoperiodicFaceSF(dm, num_face_sfs, (PetscSF *)sfs)); // for the compose function effect on dm
185   }
186   PetscCall(DMDestroyLabelLinkList_Internal(dm));
187   PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
188   PetscCall(DMGetCoarseDM(dmNew, &coarseDM));
189   PetscCall(DMSetCoarseDM(dm, coarseDM));
190   PetscCall(DMPlexCopyEGADSInfo_Internal(dmNew, dm));
191   PetscCall(DMDestroy(ndm));
192   PetscFunctionReturn(PETSC_SUCCESS);
193 }
194 
195 /* Swap dm with the contents of dmNew
196    - Swap the DM_Plex structure
197    - Swap the coordinates
198    - Swap the point PetscSF
199 */
DMPlexSwap_Static(DM dmA,DM dmB)200 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
201 {
202   DM          coordDMA, coordDMB;
203   Vec         coordsA, coordsB;
204   PetscSF     sfA, sfB;
205   DMField     fieldTmp;
206   void       *tmp;
207   DMLabelLink listTmp;
208   DMLabel     depthTmp;
209   PetscInt    tmpI;
210 
211   PetscFunctionBegin;
212   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
213   PetscCall(DMGetPointSF(dmA, &sfA));
214   PetscCall(DMGetPointSF(dmB, &sfB));
215   PetscCall(PetscObjectReference((PetscObject)sfA));
216   PetscCall(DMSetPointSF(dmA, sfB));
217   PetscCall(DMSetPointSF(dmB, sfA));
218   PetscCall(PetscObjectDereference((PetscObject)sfA));
219 
220   PetscCall(DMGetCoordinateDM(dmA, &coordDMA));
221   PetscCall(DMGetCoordinateDM(dmB, &coordDMB));
222   PetscCall(PetscObjectReference((PetscObject)coordDMA));
223   PetscCall(DMSetCoordinateDM(dmA, coordDMB));
224   PetscCall(DMSetCoordinateDM(dmB, coordDMA));
225   PetscCall(PetscObjectDereference((PetscObject)coordDMA));
226 
227   PetscCall(DMGetCoordinatesLocal(dmA, &coordsA));
228   PetscCall(DMGetCoordinatesLocal(dmB, &coordsB));
229   PetscCall(PetscObjectReference((PetscObject)coordsA));
230   PetscCall(DMSetCoordinatesLocal(dmA, coordsB));
231   PetscCall(DMSetCoordinatesLocal(dmB, coordsA));
232   PetscCall(PetscObjectDereference((PetscObject)coordsA));
233 
234   PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA));
235   PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB));
236   PetscCall(PetscObjectReference((PetscObject)coordDMA));
237   PetscCall(DMSetCellCoordinateDM(dmA, coordDMB));
238   PetscCall(DMSetCellCoordinateDM(dmB, coordDMA));
239   PetscCall(PetscObjectDereference((PetscObject)coordDMA));
240 
241   PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA));
242   PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB));
243   PetscCall(PetscObjectReference((PetscObject)coordsA));
244   PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB));
245   PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA));
246   PetscCall(PetscObjectDereference((PetscObject)coordsA));
247 
248   PetscCall(DMPlexSwapEGADSInfo_Private(dmA, dmB));
249 
250   fieldTmp                  = dmA->coordinates[0].field;
251   dmA->coordinates[0].field = dmB->coordinates[0].field;
252   dmB->coordinates[0].field = fieldTmp;
253   fieldTmp                  = dmA->coordinates[1].field;
254   dmA->coordinates[1].field = dmB->coordinates[1].field;
255   dmB->coordinates[1].field = fieldTmp;
256   tmp                       = dmA->data;
257   dmA->data                 = dmB->data;
258   dmB->data                 = tmp;
259   listTmp                   = dmA->labels;
260   dmA->labels               = dmB->labels;
261   dmB->labels               = listTmp;
262   depthTmp                  = dmA->depthLabel;
263   dmA->depthLabel           = dmB->depthLabel;
264   dmB->depthLabel           = depthTmp;
265   depthTmp                  = dmA->celltypeLabel;
266   dmA->celltypeLabel        = dmB->celltypeLabel;
267   dmB->celltypeLabel        = depthTmp;
268   tmpI                      = dmA->levelup;
269   dmA->levelup              = dmB->levelup;
270   dmB->levelup              = tmpI;
271   PetscFunctionReturn(PETSC_SUCCESS);
272 }
273 
DMPlexInterpolateInPlace_Internal(DM dm)274 PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm)
275 {
276   DM idm;
277 
278   PetscFunctionBegin;
279   PetscCall(DMPlexInterpolate(dm, &idm));
280   PetscCall(DMPlexCopyCoordinates(dm, idm));
281   PetscCall(DMPlexReplace_Internal(dm, &idm));
282   PetscFunctionReturn(PETSC_SUCCESS);
283 }
284 
285 /*@C
286   DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates
287 
288   Collective
289 
290   Input Parameters:
291 + dm        - The `DMPLEX`
292 . degree    - The degree of the finite element or `PETSC_DECIDE`
293 . localized - Flag to create a localized (DG) coordinate space
294 - project   - Flag to project current coordinates into the space
295 
296   Level: advanced
297 
298 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPointFn`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()`, `DMPlexSetCoordinateMap()`
299 @*/
DMPlexCreateCoordinateSpace(DM dm,PetscInt degree,PetscBool localized,PetscBool project)300 PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscBool localized, PetscBool project)
301 {
302   PetscFE  fe = NULL;
303   DM       cdm;
304   PetscInt dim, cdim, dE, qorder, height;
305 
306   PetscFunctionBegin;
307   PetscCall(DMGetDimension(dm, &dim));
308   cdim = dim;
309   PetscCall(DMGetCoordinateDim(dm, &dE));
310   qorder = degree;
311   PetscCall(DMGetCoordinateDM(dm, &cdm));
312   PetscObjectOptionsBegin((PetscObject)cdm);
313   PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0));
314   PetscCall(PetscOptionsBoundedInt("-dm_plex_coordinate_dim", "Set the coordinate dimension", "DMPlexCreateCoordinateSpace", cdim, &cdim, NULL, dim));
315   PetscOptionsEnd();
316   PetscCall(DMPlexGetVTKCellHeight(dm, &height));
317   if (cdim > dim) {
318     DM           cdm;
319     PetscSection cs, csNew;
320     Vec          coordinates, coordinatesNew;
321     VecType      vectype;
322     IS           idx;
323     PetscInt    *indices;
324     PetscInt     bs, n;
325 
326     // Recreate coordinate section
327     {
328       const char *fieldName = NULL, *compName = NULL;
329       PetscInt    Nc, pStart, pEnd;
330 
331       PetscCall(DMGetCoordinateDM(dm, &cdm));
332       PetscCall(DMGetLocalSection(cdm, &cs));
333       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cs), &csNew));
334       PetscCall(PetscSectionSetNumFields(csNew, 1));
335       PetscCall(PetscSectionGetFieldName(cs, 0, &fieldName));
336       PetscCall(PetscSectionSetFieldName(csNew, 0, fieldName));
337       PetscCall(PetscSectionGetFieldComponents(cs, 0, &Nc));
338       PetscCall(PetscSectionSetFieldComponents(csNew, 0, cdim));
339       for (PetscInt c = 0; c < Nc; ++c) {
340         PetscCall(PetscSectionGetComponentName(cs, 0, c, &compName));
341         PetscCall(PetscSectionSetComponentName(csNew, 0, c, compName));
342       }
343       PetscCall(PetscSectionGetChart(cs, &pStart, &pEnd));
344       PetscCall(PetscSectionSetChart(csNew, pStart, pEnd));
345       for (PetscInt p = pStart; p < pEnd; ++p) {
346         PetscInt dof;
347 
348         PetscCall(PetscSectionGetDof(cs, p, &dof));
349         if (dof) {
350           PetscCall(PetscSectionSetDof(csNew, p, cdim));
351           PetscCall(PetscSectionSetFieldDof(csNew, p, 0, cdim));
352         }
353       }
354       PetscCall(PetscSectionSetUp(csNew));
355     }
356     PetscCall(DMSetLocalSection(cdm, csNew));
357     PetscCall(PetscSectionDestroy(&csNew));
358     // Reset coordinate dimension for coordinate DM
359     PetscCall(DMSetCoordinateDim(cdm, cdim));
360     PetscCall(DMSetCoordinateField(cdm, NULL));
361     // Inject coordinates into higher dimension
362     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
363     PetscCall(VecGetBlockSize(coordinates, &bs));
364     PetscCheck(bs == dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We can only inject simple coordinates into a higher dimension");
365     PetscCall(VecCreate(PetscObjectComm((PetscObject)coordinates), &coordinatesNew));
366     PetscCall(VecGetType(coordinates, &vectype));
367     PetscCall(VecSetType(coordinatesNew, vectype));
368     PetscCall(VecGetLocalSize(coordinates, &n));
369     PetscCheck(!(n % bs), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We can only inject simple coordinates into a higher dimension");
370     n /= bs;
371     PetscCall(VecSetSizes(coordinatesNew, n * cdim, PETSC_DETERMINE));
372     PetscCall(VecSetUp(coordinatesNew));
373     PetscCall(PetscMalloc1(n * bs, &indices));
374     for (PetscInt i = 0; i < n; ++i)
375       for (PetscInt b = 0; b < bs; ++b) indices[i * bs + b] = i * cdim + b;
376     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n * bs, indices, PETSC_OWN_POINTER, &idx));
377     PetscCall(VecISCopy(coordinatesNew, idx, SCATTER_FORWARD, coordinates));
378     PetscCall(ISDestroy(&idx));
379     PetscCall(DMSetCoordinatesLocal(dm, coordinatesNew));
380     PetscCall(VecDestroy(&coordinatesNew));
381     PetscCall(DMSetCoordinateDim(dm, cdim));
382     {
383       PetscInt gn;
384 
385       PetscCall(DMGetCoordinates(dm, &coordinatesNew));
386       PetscCall(VecGetLocalSize(coordinatesNew, &gn));
387       PetscCheck(gn == n * cdim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Global coordinate size %" PetscInt_FMT " != %" PetscInt_FMT "local coordinate size", gn, n * cdim);
388     }
389     dE      = cdim;
390     project = PETSC_FALSE;
391   }
392   if (degree >= 0) {
393     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
394     PetscInt       cStart, cEnd, gct;
395 
396     PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
397     if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct));
398     gct = (PetscInt)ct;
399     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm)));
400     ct = (DMPolytopeType)gct;
401     // Work around current bug in PetscDualSpaceSetUp_Lagrange()
402     //   Can be seen in plex_tutorials-ex10_1
403     if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) {
404       PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe));
405       if (localized) {
406         PetscFE dgfe = NULL;
407 
408         PetscCall(PetscFECreateBrokenElement(fe, &dgfe));
409         PetscCall(PetscFEDestroy(&fe));
410         fe = dgfe;
411       }
412     }
413   }
414   PetscCall(DMSetCoordinateDisc(dm, fe, localized, project));
415   PetscCall(PetscFEDestroy(&fe));
416   PetscFunctionReturn(PETSC_SUCCESS);
417 }
418 
419 /*@
420   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.
421 
422   Collective
423 
424   Input Parameters:
425 + comm            - The communicator for the `DM` object
426 . dim             - The spatial dimension
427 . simplex         - Flag for simplicial cells, otherwise they are tensor product cells
428 . interpolate     - Flag to create intermediate mesh pieces (edges, faces)
429 - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell
430 
431   Output Parameter:
432 . newdm - The `DM` object
433 
434   Level: beginner
435 
436 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()`
437 @*/
DMPlexCreateDoublet(MPI_Comm comm,PetscInt dim,PetscBool simplex,PetscBool interpolate,PetscReal refinementLimit,DM * newdm)438 PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm)
439 {
440   DM          dm;
441   PetscMPIInt rank;
442 
443   PetscFunctionBegin;
444   PetscCall(DMCreate(comm, &dm));
445   PetscCall(DMSetType(dm, DMPLEX));
446   PetscCall(DMSetDimension(dm, dim));
447   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
448   PetscCallMPI(MPI_Comm_rank(comm, &rank));
449   switch (dim) {
450   case 2:
451     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular"));
452     else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral"));
453     break;
454   case 3:
455     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral"));
456     else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral"));
457     break;
458   default:
459     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
460   }
461   if (rank) {
462     PetscInt numPoints[2] = {0, 0};
463     PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL));
464   } else {
465     switch (dim) {
466     case 2:
467       if (simplex) {
468         PetscInt    numPoints[2]        = {4, 2};
469         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
470         PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
471         PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
472         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};
473 
474         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
475       } else {
476         PetscInt    numPoints[2]        = {6, 2};
477         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
478         PetscInt    cones[8]            = {2, 3, 4, 5, 3, 6, 7, 4};
479         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
480         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};
481 
482         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
483       }
484       break;
485     case 3:
486       if (simplex) {
487         PetscInt    numPoints[2]        = {5, 2};
488         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
489         PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
490         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
491         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};
492 
493         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
494       } else {
495         PetscInt    numPoints[2]         = {12, 2};
496         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
497         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
498         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
499         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};
500 
501         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
502       }
503       break;
504     default:
505       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
506     }
507   }
508   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
509   *newdm = dm;
510   if (refinementLimit > 0.0) {
511     DM          rdm;
512     const char *name;
513 
514     PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE));
515     PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit));
516     PetscCall(DMRefine(*newdm, comm, &rdm));
517     PetscCall(PetscObjectGetName((PetscObject)*newdm, &name));
518     PetscCall(PetscObjectSetName((PetscObject)rdm, name));
519     PetscCall(DMDestroy(newdm));
520     *newdm = rdm;
521   }
522   if (interpolate) {
523     DM idm;
524 
525     PetscCall(DMPlexInterpolate(*newdm, &idm));
526     PetscCall(DMDestroy(newdm));
527     *newdm = idm;
528   }
529   PetscFunctionReturn(PETSC_SUCCESS);
530 }
531 
DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm,const PetscReal lower[],const PetscReal upper[],const PetscInt edges[])532 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
533 {
534   const PetscInt numVertices    = 2;
535   PetscInt       markerRight    = 1;
536   PetscInt       markerLeft     = 1;
537   PetscBool      markerSeparate = PETSC_FALSE;
538   Vec            coordinates;
539   PetscSection   coordSection;
540   PetscScalar   *coords;
541   PetscInt       coordSize;
542   PetscMPIInt    rank;
543   PetscInt       cdim = 1, v;
544 
545   PetscFunctionBegin;
546   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
547   if (markerSeparate) {
548     markerRight = 2;
549     markerLeft  = 1;
550   }
551   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
552   if (rank == 0) {
553     PetscCall(DMPlexSetChart(dm, 0, numVertices));
554     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
555     PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft));
556     PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight));
557   }
558   PetscCall(DMPlexSymmetrize(dm));
559   PetscCall(DMPlexStratify(dm));
560   /* Build coordinates */
561   PetscCall(DMSetCoordinateDim(dm, cdim));
562   PetscCall(DMGetCoordinateSection(dm, &coordSection));
563   PetscCall(PetscSectionSetNumFields(coordSection, 1));
564   PetscCall(PetscSectionSetChart(coordSection, 0, numVertices));
565   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
566   for (v = 0; v < numVertices; ++v) {
567     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
568     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
569   }
570   PetscCall(PetscSectionSetUp(coordSection));
571   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
572   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
573   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
574   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
575   PetscCall(VecSetBlockSize(coordinates, cdim));
576   PetscCall(VecSetType(coordinates, VECSTANDARD));
577   PetscCall(VecGetArray(coordinates, &coords));
578   coords[0] = lower[0];
579   coords[1] = upper[0];
580   PetscCall(VecRestoreArray(coordinates, &coords));
581   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
582   PetscCall(VecDestroy(&coordinates));
583   PetscFunctionReturn(PETSC_SUCCESS);
584 }
585 
DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm,const PetscReal lower[],const PetscReal upper[],const PetscInt edges[])586 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
587 {
588   const PetscInt numVertices    = (edges[0] + 1) * (edges[1] + 1);
589   const PetscInt numEdges       = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1];
590   PetscInt       markerTop      = 1;
591   PetscInt       markerBottom   = 1;
592   PetscInt       markerRight    = 1;
593   PetscInt       markerLeft     = 1;
594   PetscBool      markerSeparate = PETSC_FALSE;
595   Vec            coordinates;
596   PetscSection   coordSection;
597   PetscScalar   *coords;
598   PetscInt       coordSize;
599   PetscMPIInt    rank;
600   PetscInt       v, vx, vy;
601 
602   PetscFunctionBegin;
603   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
604   if (markerSeparate) {
605     markerTop    = 3;
606     markerBottom = 1;
607     markerRight  = 2;
608     markerLeft   = 4;
609   }
610   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
611   if (rank == 0) {
612     PetscInt e, ex, ey;
613 
614     PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices));
615     for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
616     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
617     for (vx = 0; vx <= edges[0]; vx++) {
618       for (ey = 0; ey < edges[1]; ey++) {
619         PetscInt edge   = vx * edges[1] + ey + edges[0] * (edges[1] + 1);
620         PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges;
621         PetscInt cone[2];
622 
623         cone[0] = vertex;
624         cone[1] = vertex + edges[0] + 1;
625         PetscCall(DMPlexSetCone(dm, edge, cone));
626         if (vx == edges[0]) {
627           PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
628           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
629           if (ey == edges[1] - 1) {
630             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
631             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight));
632           }
633         } else if (vx == 0) {
634           PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
635           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
636           if (ey == edges[1] - 1) {
637             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
638             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft));
639           }
640         }
641       }
642     }
643     for (vy = 0; vy <= edges[1]; vy++) {
644       for (ex = 0; ex < edges[0]; ex++) {
645         PetscInt edge   = vy * edges[0] + ex;
646         PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges;
647         PetscInt cone[2];
648 
649         cone[0] = vertex;
650         cone[1] = vertex + 1;
651         PetscCall(DMPlexSetCone(dm, edge, cone));
652         if (vy == edges[1]) {
653           PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
654           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
655           if (ex == edges[0] - 1) {
656             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
657             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop));
658           }
659         } else if (vy == 0) {
660           PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
661           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
662           if (ex == edges[0] - 1) {
663             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
664             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom));
665           }
666         }
667       }
668     }
669   }
670   PetscCall(DMPlexSymmetrize(dm));
671   PetscCall(DMPlexStratify(dm));
672   /* Build coordinates */
673   PetscCall(DMSetCoordinateDim(dm, 2));
674   PetscCall(DMGetCoordinateSection(dm, &coordSection));
675   PetscCall(PetscSectionSetNumFields(coordSection, 1));
676   PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices));
677   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
678   for (v = numEdges; v < numEdges + numVertices; ++v) {
679     PetscCall(PetscSectionSetDof(coordSection, v, 2));
680     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
681   }
682   PetscCall(PetscSectionSetUp(coordSection));
683   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
684   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
685   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
686   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
687   PetscCall(VecSetBlockSize(coordinates, 2));
688   PetscCall(VecSetType(coordinates, VECSTANDARD));
689   PetscCall(VecGetArray(coordinates, &coords));
690   for (vy = 0; vy <= edges[1]; ++vy) {
691     for (vx = 0; vx <= edges[0]; ++vx) {
692       coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx;
693       coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy;
694     }
695   }
696   PetscCall(VecRestoreArray(coordinates, &coords));
697   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
698   PetscCall(VecDestroy(&coordinates));
699   PetscFunctionReturn(PETSC_SUCCESS);
700 }
701 
DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm,const PetscReal lower[],const PetscReal upper[],const PetscInt faces[])702 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
703 {
704   PetscInt     vertices[3], numVertices;
705   PetscInt     numFaces       = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2];
706   PetscInt     markerTop      = 1;
707   PetscInt     markerBottom   = 1;
708   PetscInt     markerFront    = 1;
709   PetscInt     markerBack     = 1;
710   PetscInt     markerRight    = 1;
711   PetscInt     markerLeft     = 1;
712   PetscBool    markerSeparate = PETSC_FALSE;
713   Vec          coordinates;
714   PetscSection coordSection;
715   PetscScalar *coords;
716   PetscInt     coordSize;
717   PetscMPIInt  rank;
718   PetscInt     v, vx, vy, vz;
719   PetscInt     voffset, iface = 0, cone[4];
720 
721   PetscFunctionBegin;
722   PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side");
723   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
724   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
725   if (markerSeparate) {
726     markerBottom = 1;
727     markerTop    = 2;
728     markerFront  = 3;
729     markerBack   = 4;
730     markerRight  = 5;
731     markerLeft   = 6;
732   }
733   vertices[0] = faces[0] + 1;
734   vertices[1] = faces[1] + 1;
735   vertices[2] = faces[2] + 1;
736   numVertices = vertices[0] * vertices[1] * vertices[2];
737   if (rank == 0) {
738     PetscInt f;
739 
740     PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices));
741     for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
742     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
743 
744     /* Side 0 (Top) */
745     for (vy = 0; vy < faces[1]; vy++) {
746       for (vx = 0; vx < faces[0]; vx++) {
747         voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx;
748         cone[0] = voffset;
749         cone[1] = voffset + 1;
750         cone[2] = voffset + vertices[0] + 1;
751         cone[3] = voffset + vertices[0];
752         PetscCall(DMPlexSetCone(dm, iface, cone));
753         PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop));
754         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop));
755         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop));
756         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop));
757         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop));
758         iface++;
759       }
760     }
761 
762     /* Side 1 (Bottom) */
763     for (vy = 0; vy < faces[1]; vy++) {
764       for (vx = 0; vx < faces[0]; vx++) {
765         voffset = numFaces + vy * (faces[0] + 1) + vx;
766         cone[0] = voffset + 1;
767         cone[1] = voffset;
768         cone[2] = voffset + vertices[0];
769         cone[3] = voffset + vertices[0] + 1;
770         PetscCall(DMPlexSetCone(dm, iface, cone));
771         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom));
772         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom));
773         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom));
774         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom));
775         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom));
776         iface++;
777       }
778     }
779 
780     /* Side 2 (Front) */
781     for (vz = 0; vz < faces[2]; vz++) {
782       for (vx = 0; vx < faces[0]; vx++) {
783         voffset = numFaces + vz * vertices[0] * vertices[1] + vx;
784         cone[0] = voffset;
785         cone[1] = voffset + 1;
786         cone[2] = voffset + vertices[0] * vertices[1] + 1;
787         cone[3] = voffset + vertices[0] * vertices[1];
788         PetscCall(DMPlexSetCone(dm, iface, cone));
789         PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront));
790         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront));
791         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront));
792         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront));
793         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront));
794         iface++;
795       }
796     }
797 
798     /* Side 3 (Back) */
799     for (vz = 0; vz < faces[2]; vz++) {
800       for (vx = 0; vx < faces[0]; vx++) {
801         voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx;
802         cone[0] = voffset + vertices[0] * vertices[1];
803         cone[1] = voffset + vertices[0] * vertices[1] + 1;
804         cone[2] = voffset + 1;
805         cone[3] = voffset;
806         PetscCall(DMPlexSetCone(dm, iface, cone));
807         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack));
808         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack));
809         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack));
810         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack));
811         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack));
812         iface++;
813       }
814     }
815 
816     /* Side 4 (Left) */
817     for (vz = 0; vz < faces[2]; vz++) {
818       for (vy = 0; vy < faces[1]; vy++) {
819         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0];
820         cone[0] = voffset;
821         cone[1] = voffset + vertices[0] * vertices[1];
822         cone[2] = voffset + vertices[0] * vertices[1] + vertices[0];
823         cone[3] = voffset + vertices[0];
824         PetscCall(DMPlexSetCone(dm, iface, cone));
825         PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft));
826         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft));
827         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft));
828         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft));
829         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft));
830         iface++;
831       }
832     }
833 
834     /* Side 5 (Right) */
835     for (vz = 0; vz < faces[2]; vz++) {
836       for (vy = 0; vy < faces[1]; vy++) {
837         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0];
838         cone[0] = voffset + vertices[0] * vertices[1];
839         cone[1] = voffset;
840         cone[2] = voffset + vertices[0];
841         cone[3] = voffset + vertices[0] * vertices[1] + vertices[0];
842         PetscCall(DMPlexSetCone(dm, iface, cone));
843         PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight));
844         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight));
845         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight));
846         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight));
847         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight));
848         iface++;
849       }
850     }
851   }
852   PetscCall(DMPlexSymmetrize(dm));
853   PetscCall(DMPlexStratify(dm));
854   /* Build coordinates */
855   PetscCall(DMSetCoordinateDim(dm, 3));
856   PetscCall(DMGetCoordinateSection(dm, &coordSection));
857   PetscCall(PetscSectionSetNumFields(coordSection, 1));
858   PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices));
859   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
860   for (v = numFaces; v < numFaces + numVertices; ++v) {
861     PetscCall(PetscSectionSetDof(coordSection, v, 3));
862     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
863   }
864   PetscCall(PetscSectionSetUp(coordSection));
865   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
866   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
867   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
868   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
869   PetscCall(VecSetBlockSize(coordinates, 3));
870   PetscCall(VecSetType(coordinates, VECSTANDARD));
871   PetscCall(VecGetArray(coordinates, &coords));
872   for (vz = 0; vz <= faces[2]; ++vz) {
873     for (vy = 0; vy <= faces[1]; ++vy) {
874       for (vx = 0; vx <= faces[0]; ++vx) {
875         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx;
876         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy;
877         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz;
878       }
879     }
880   }
881   PetscCall(VecRestoreArray(coordinates, &coords));
882   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
883   PetscCall(VecDestroy(&coordinates));
884   PetscFunctionReturn(PETSC_SUCCESS);
885 }
886 
DMPlexCreateBoxSurfaceMesh_Internal(DM dm,PetscInt dim,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],PetscBool interpolate)887 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate)
888 {
889   PetscFunctionBegin;
890   PetscValidLogicalCollectiveInt(dm, dim, 2);
891   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
892   PetscCall(DMSetDimension(dm, dim - 1));
893   PetscCall(DMSetCoordinateDim(dm, dim));
894   switch (dim) {
895   case 1:
896     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces));
897     break;
898   case 2:
899     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces));
900     break;
901   case 3:
902     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces));
903     break;
904   default:
905     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim);
906   }
907   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
908   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
909   PetscFunctionReturn(PETSC_SUCCESS);
910 }
911 
912 /*@C
913   DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra).
914 
915   Collective
916 
917   Input Parameters:
918 + comm        - The communicator for the `DM` object
919 . dim         - The spatial dimension of the box, so the resulting mesh is has dimension `dim`-1
920 . faces       - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
921 . lower       - The lower left corner, or `NULL` for (0, 0, 0)
922 . upper       - The upper right corner, or `NULL` for (1, 1, 1)
923 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
924 
925   Output Parameter:
926 . dm - The `DM` object
927 
928   Level: beginner
929 
930 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()`
931 @*/
DMPlexCreateBoxSurfaceMesh(MPI_Comm comm,PetscInt dim,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],PetscBool interpolate,DM * dm)932 PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm)
933 {
934   PetscInt  fac[3] = {1, 1, 1};
935   PetscReal low[3] = {0, 0, 0};
936   PetscReal upp[3] = {1, 1, 1};
937 
938   PetscFunctionBegin;
939   PetscCall(DMCreate(comm, dm));
940   PetscCall(DMSetType(*dm, DMPLEX));
941   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate));
942   PetscFunctionReturn(PETSC_SUCCESS);
943 }
944 
DMPlexCreateLineMesh_Internal(DM dm,PetscInt segments,PetscReal lower,PetscReal upper,DMBoundaryType bd)945 static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd)
946 {
947   PetscInt     i, fStart, fEnd, numCells = 0, numVerts = 0;
948   PetscInt     numPoints[2], *coneSize, *cones, *coneOrientations;
949   PetscScalar *vertexCoords;
950   PetscReal    L, maxCell;
951   PetscBool    markerSeparate = PETSC_FALSE;
952   PetscInt     markerLeft = 1, faceMarkerLeft = 1;
953   PetscInt     markerRight = 1, faceMarkerRight = 2;
954   PetscBool    wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE;
955   PetscMPIInt  rank;
956 
957   PetscFunctionBegin;
958   PetscAssertPointer(dm, 1);
959 
960   PetscCall(DMSetDimension(dm, 1));
961   PetscCall(DMCreateLabel(dm, "marker"));
962   PetscCall(DMCreateLabel(dm, "Face Sets"));
963 
964   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
965   if (rank == 0) numCells = segments;
966   if (rank == 0) numVerts = segments + (wrap ? 0 : 1);
967 
968   numPoints[0] = numVerts;
969   numPoints[1] = numCells;
970   PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords));
971   PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts));
972   for (i = 0; i < numCells; ++i) coneSize[i] = 2;
973   for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0;
974   for (i = 0; i < numCells; ++i) {
975     cones[2 * i]     = numCells + i % numVerts;
976     cones[2 * i + 1] = numCells + (i + 1) % numVerts;
977   }
978   for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells);
979   PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
980   PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords));
981 
982   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
983   if (markerSeparate) {
984     markerLeft  = faceMarkerLeft;
985     markerRight = faceMarkerRight;
986   }
987   if (!wrap && rank == 0) {
988     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
989     PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft));
990     PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight));
991     PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft));
992     PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight));
993   }
994   if (wrap) {
995     L       = upper - lower;
996     maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments));
997     PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L));
998   }
999   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1000   PetscFunctionReturn(PETSC_SUCCESS);
1001 }
1002 
1003 // Creates "Face Sets" label based on the standard box labeling conventions
DMPlexSetBoxLabel_Internal(DM dm,const DMBoundaryType periodicity[])1004 static PetscErrorCode DMPlexSetBoxLabel_Internal(DM dm, const DMBoundaryType periodicity[])
1005 {
1006   DM              cdm;
1007   PetscSection    csection;
1008   Vec             coordinates;
1009   DMLabel         label;
1010   IS              faces_is;
1011   PetscInt        dim, num_face = 0;
1012   const PetscInt *faces;
1013   PetscInt        faceMarkerBottom, faceMarkerTop, faceMarkerFront, faceMarkerBack, faceMarkerRight, faceMarkerLeft;
1014 
1015   PetscFunctionBeginUser;
1016   PetscCall(DMGetDimension(dm, &dim));
1017   PetscCheck((dim == 2) || (dim == 3), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMPlex box labeling only supports 2D and 3D meshes, received DM of dimension %" PetscInt_FMT, dim);
1018   // Get Face Sets label
1019   PetscCall(DMGetLabel(dm, "Face Sets", &label));
1020   if (label) {
1021     PetscCall(DMLabelReset(label));
1022   } else {
1023     PetscCall(DMCreateLabel(dm, "Face Sets"));
1024     PetscCall(DMGetLabel(dm, "Face Sets", &label));
1025   }
1026   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
1027   PetscCall(DMGetStratumIS(dm, "Face Sets", 1, &faces_is));
1028 
1029   switch (dim) {
1030   case 2:
1031     faceMarkerTop    = 3;
1032     faceMarkerBottom = 1;
1033     faceMarkerRight  = 2;
1034     faceMarkerLeft   = 4;
1035     break;
1036   case 3:
1037     faceMarkerBottom = 1;
1038     faceMarkerTop    = 2;
1039     faceMarkerFront  = 3;
1040     faceMarkerBack   = 4;
1041     faceMarkerRight  = 5;
1042     faceMarkerLeft   = 6;
1043     break;
1044   default:
1045     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
1046   }
1047 
1048   if (faces_is) PetscCall(ISGetLocalSize(faces_is, &num_face));
1049   if (faces_is) PetscCall(ISGetIndices(faces_is, &faces));
1050   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1051   PetscCall(DMGetCoordinateDM(dm, &cdm));
1052   PetscCall(DMGetLocalSection(cdm, &csection));
1053   for (PetscInt f = 0; f < num_face; ++f) {
1054     PetscScalar *coords = NULL;
1055     PetscInt     face = faces[f], flip = 1, label_value = -1, coords_size;
1056 
1057     { // Determine if orientation of face is flipped
1058       PetscInt        num_cells_support, num_faces, start = -1;
1059       const PetscInt *orients, *cell_faces, *cells;
1060 
1061       PetscCall(DMPlexGetSupport(dm, face, &cells));
1062       PetscCall(DMPlexGetSupportSize(dm, face, &num_cells_support));
1063       PetscCheck(num_cells_support == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Expected one cell in support of exterior face, but got %" PetscInt_FMT " cells", num_cells_support);
1064       PetscCall(DMPlexGetCone(dm, cells[0], &cell_faces));
1065       PetscCall(DMPlexGetConeSize(dm, cells[0], &num_faces));
1066       for (PetscInt i = 0; i < num_faces; i++) {
1067         if (cell_faces[i] == face) start = i;
1068       }
1069       PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Could not find face %" PetscInt_FMT " in cone of its support", face);
1070       PetscCall(DMPlexGetConeOrientation(dm, cells[0], &orients));
1071       if (orients[start] < 0) flip = -1;
1072     }
1073 
1074     // Cannot use DMPlexComputeCellGeometryFVM() for high-order geometry, so must calculate normal vectors manually
1075     // Use the vertices (depth 0) of coordinate DM to calculate normal vector
1076     PetscCall(DMPlexVecGetClosureAtDepth(cdm, csection, coordinates, face, 0, &coords_size, &coords));
1077     switch (dim) {
1078     case 2: {
1079       PetscScalar vec[2];
1080 
1081       for (PetscInt d = 0; d < dim; ++d) vec[d] = flip * (PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1082       PetscScalar normal[] = {vec[1], -vec[0]};
1083       if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[1])) {
1084         label_value = PetscRealPart(normal[0]) > 0 ? faceMarkerRight : faceMarkerLeft;
1085       } else {
1086         label_value = PetscRealPart(normal[1]) > 0 ? faceMarkerTop : faceMarkerBottom;
1087       }
1088     } break;
1089     case 3: {
1090       PetscScalar vec1[3], vec2[3], normal[3];
1091 
1092       for (PetscInt d = 0; d < dim; ++d) {
1093         vec1[d] = PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]);
1094         vec2[d] = PetscRealPart(coords[2 * dim + d]) - PetscRealPart(coords[1 * dim + d]);
1095       }
1096 
1097       // Calculate normal vector via cross-product
1098       normal[0] = flip * ((vec1[1] * vec2[2]) - (vec1[2] * vec2[1]));
1099       normal[1] = flip * ((vec1[2] * vec2[0]) - (vec1[0] * vec2[2]));
1100       normal[2] = flip * ((vec1[0] * vec2[1]) - (vec1[1] * vec2[0]));
1101 
1102       if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[1])) {
1103         if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[2])) {
1104           label_value = PetscRealPart(normal[0]) > 0 ? faceMarkerRight : faceMarkerLeft;
1105         } else {
1106           label_value = PetscRealPart(normal[2]) > 0 ? faceMarkerTop : faceMarkerBottom;
1107         }
1108       } else {
1109         if (PetscAbsScalar(normal[1]) > PetscAbsScalar(normal[2])) {
1110           label_value = PetscRealPart(normal[1]) > 0 ? faceMarkerBack : faceMarkerFront;
1111         } else {
1112           label_value = PetscRealPart(normal[2]) > 0 ? faceMarkerTop : faceMarkerBottom;
1113         }
1114       }
1115     } break;
1116     }
1117 
1118     PetscInt previous_label_value; // always 1 due to DMPlexMarkBoundaryFaces call above
1119     PetscCall(DMGetLabelValue(dm, "Face Sets", face, &previous_label_value));
1120     PetscCall(DMClearLabelValue(dm, "Face Sets", face, previous_label_value));
1121     PetscCall(DMSetLabelValue(dm, "Face Sets", face, label_value));
1122     PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords));
1123   }
1124   if (faces_is) PetscCall(ISRestoreIndices(faces_is, &faces));
1125   PetscCall(ISDestroy(&faces_is));
1126 
1127   // Create Isoperiodic SF from newly-created face labels
1128   PetscSF     periodicsfs[3];
1129   PetscInt    periodic_sf_index  = 0;
1130   PetscScalar transform[3][4][4] = {{{0.}}};
1131   for (PetscInt d = 0; d < dim; d++) {
1132     IS              donor_is, periodic_is;
1133     const PetscInt *donor_faces = NULL, *periodic_faces = NULL;
1134     PetscInt        num_donor = 0, num_periodic = 0;
1135     PetscSF         centroidsf;
1136     PetscReal       donor_to_periodic_distance;
1137     const PetscInt  face_pairings[2][3][2] = {
1138       // 2D face pairings, {donor, periodic}
1139       {{4, 2}, {1, 3}},
1140       // 3D face pairings
1141       {{5, 6}, {3, 4}, {1, 2}}
1142     };
1143 
1144     if (periodicity[d] != DM_BOUNDARY_PERIODIC) continue;
1145     {
1146       // Compute centroidsf, which is the mapping from donor faces to periodic faces
1147       // Matches the centroid of the faces together, ignoring the periodic direction component (which should not match between donor and periodic face)
1148       PetscInt     coords_size, centroid_comps = dim - 1;
1149       PetscScalar *coords = NULL;
1150       PetscReal   *donor_centroids, *periodic_centroids;
1151       PetscReal    loc_periodic[2] = {PETSC_MIN_REAL, PETSC_MIN_REAL}, loc_periodic_global[2]; // Location of donor (0) and periodic (1) faces in periodic direction
1152 
1153       PetscCall(DMGetStratumIS(dm, "Face Sets", face_pairings[dim - 2][d][0], &donor_is));
1154       PetscCall(DMGetStratumIS(dm, "Face Sets", face_pairings[dim - 2][d][1], &periodic_is));
1155       if (donor_is) {
1156         PetscCall(ISGetLocalSize(donor_is, &num_donor));
1157         PetscCall(ISGetIndices(donor_is, &donor_faces));
1158       }
1159       if (periodic_is) {
1160         PetscCall(ISGetLocalSize(periodic_is, &num_periodic));
1161         PetscCall(ISGetIndices(periodic_is, &periodic_faces));
1162       }
1163       PetscCall(PetscCalloc2(num_donor * centroid_comps, &donor_centroids, num_periodic * centroid_comps, &periodic_centroids));
1164       for (PetscInt f = 0; f < num_donor; f++) {
1165         PetscInt face = donor_faces[f], num_coords;
1166         PetscCall(DMPlexVecGetClosureAtDepth(cdm, csection, coordinates, face, 0, &coords_size, &coords));
1167         num_coords = coords_size / dim;
1168         for (PetscInt c = 0; c < num_coords; c++) {
1169           PetscInt comp_index = 0;
1170           loc_periodic[0]     = PetscRealPart(coords[c * dim + d]);
1171           for (PetscInt i = 0; i < dim; i++) {
1172             if (i == d) continue; // Periodic direction not used for centroid calculation
1173             donor_centroids[f * centroid_comps + comp_index] += PetscRealPart(coords[c * dim + i]) / num_coords;
1174             comp_index++;
1175           }
1176         }
1177         PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords));
1178       }
1179 
1180       for (PetscInt f = 0; f < num_periodic; f++) {
1181         PetscInt face = periodic_faces[f], num_coords;
1182         PetscCall(DMPlexVecGetClosureAtDepth(cdm, csection, coordinates, face, 0, &coords_size, &coords));
1183         num_coords = coords_size / dim;
1184         for (PetscInt c = 0; c < num_coords; c++) {
1185           PetscInt comp_index = 0;
1186           loc_periodic[1]     = PetscRealPart(coords[c * dim + d]);
1187           for (PetscInt i = 0; i < dim; i++) {
1188             if (i == d) continue; // Periodic direction not used for centroid calculation
1189             periodic_centroids[f * centroid_comps + comp_index] += PetscRealPart(coords[c * dim + i]) / num_coords;
1190             comp_index++;
1191           }
1192         }
1193         PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords));
1194       }
1195       PetscCallMPI(MPIU_Allreduce(loc_periodic, loc_periodic_global, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm)));
1196       donor_to_periodic_distance = loc_periodic_global[1] - loc_periodic_global[0];
1197 
1198       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &centroidsf));
1199       PetscCall(PetscSFSetGraphFromCoordinates(centroidsf, num_donor, num_periodic, centroid_comps, 1e-10, donor_centroids, periodic_centroids));
1200       PetscCall(PetscSFViewFromOptions(centroidsf, NULL, "-dm_plex_box_label_centroid_sf_view"));
1201       PetscCall(PetscFree2(donor_centroids, periodic_centroids));
1202     }
1203 
1204     { // Create Isoperiodic SF using centroidsSF
1205       PetscInt           pStart, pEnd;
1206       PetscInt          *leaf_faces;
1207       const PetscSFNode *firemote;
1208       PetscSFNode       *isoperiodic_leaves;
1209 
1210       PetscCall(PetscMalloc1(num_periodic, &leaf_faces));
1211       PetscCall(PetscSFBcastBegin(centroidsf, MPIU_INT, donor_faces, leaf_faces, MPI_REPLACE));
1212       PetscCall(PetscSFBcastEnd(centroidsf, MPIU_INT, donor_faces, leaf_faces, MPI_REPLACE));
1213 
1214       PetscCall(PetscMalloc1(num_periodic, &isoperiodic_leaves));
1215       PetscCall(PetscSFGetGraph(centroidsf, NULL, NULL, NULL, &firemote));
1216       for (PetscInt l = 0; l < num_periodic; ++l) {
1217         isoperiodic_leaves[l].index = leaf_faces[l];
1218         isoperiodic_leaves[l].rank  = firemote[l].rank;
1219       }
1220 
1221       PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1222       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &periodicsfs[periodic_sf_index]));
1223       PetscCall(PetscSFSetGraph(periodicsfs[periodic_sf_index], pEnd - pStart, num_periodic, (PetscInt *)periodic_faces, PETSC_COPY_VALUES, isoperiodic_leaves, PETSC_OWN_POINTER));
1224       PetscCall(PetscSFViewFromOptions(periodicsfs[periodic_sf_index], NULL, "-dm_plex_box_label_periodic_sf_view"));
1225       PetscCall(PetscFree(leaf_faces));
1226     }
1227 
1228     transform[periodic_sf_index][0][0] = 1;
1229     transform[periodic_sf_index][1][1] = 1;
1230     transform[periodic_sf_index][2][2] = 1;
1231     transform[periodic_sf_index][3][3] = 1;
1232     transform[periodic_sf_index][d][3] = donor_to_periodic_distance;
1233 
1234     periodic_sf_index++;
1235     PetscCall(PetscSFDestroy(&centroidsf));
1236     if (donor_is) {
1237       PetscCall(ISRestoreIndices(donor_is, &donor_faces));
1238       PetscCall(ISDestroy(&donor_is));
1239     }
1240     if (periodic_is) {
1241       PetscCall(ISRestoreIndices(periodic_is, &periodic_faces));
1242       PetscCall(ISDestroy(&periodic_is));
1243     }
1244     PetscCall(DMClearLabelStratum(dm, "Face Sets", face_pairings[dim - 2][d][0]));
1245     PetscCall(DMClearLabelStratum(dm, "Face Sets", face_pairings[dim - 2][d][1]));
1246   }
1247   PetscCall(DMPlexSetIsoperiodicFaceSF(dm, periodic_sf_index, periodicsfs));
1248   PetscCall(DMPlexSetIsoperiodicFaceTransform(dm, periodic_sf_index, (const PetscScalar *)transform));
1249   for (PetscInt p = 0; p < periodic_sf_index; p++) PetscCall(PetscSFDestroy(&periodicsfs[p]));
1250 
1251   { // Update coordinate DM with new Face Sets label
1252     DM      cdm;
1253     DMLabel oldFaceSets, newFaceSets;
1254     PetscCall(DMGetCoordinateDM(dm, &cdm));
1255     PetscCall(DMGetLabel(cdm, "Face Sets", &oldFaceSets));
1256     if (oldFaceSets) PetscCall(DMRemoveLabelBySelf(cdm, &oldFaceSets, PETSC_FALSE));
1257     PetscCall(DMLabelDuplicate(label, &newFaceSets));
1258     PetscCall(DMAddLabel(cdm, newFaceSets));
1259     PetscCall(DMLabelDestroy(&newFaceSets));
1260   }
1261   PetscFunctionReturn(PETSC_SUCCESS);
1262 }
1263 
DMPlexCreateSquareMesh_Simplex_CrissCross(DM dm,const PetscInt edges[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType bd[])1264 static PetscErrorCode DMPlexCreateSquareMesh_Simplex_CrissCross(DM dm, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType bd[])
1265 {
1266   PetscInt       markerTop = 1, faceMarkerTop = 3;
1267   PetscInt       markerBottom = 1, faceMarkerBottom = 1;
1268   PetscInt       markerRight = 1, faceMarkerRight = 2;
1269   PetscInt       markerLeft = 1, faceMarkerLeft = 4;
1270   PetscBool      markerSeparate = PETSC_FALSE;
1271   DMBoundaryType bdX = bd[0], bdY = bd[1];
1272   PetscMPIInt    rank;
1273 
1274   PetscFunctionBegin;
1275   PetscCheck(bdX == DM_BOUNDARY_NONE || bdX == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not implemented for boundary type %s", DMBoundaryTypes[bdX]);
1276   PetscCheck(bdY == DM_BOUNDARY_NONE || bdY == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not implemented for boundary type %s", DMBoundaryTypes[bdY]);
1277   PetscCall(DMSetDimension(dm, 2));
1278   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1279   PetscCall(DMCreateLabel(dm, "marker"));
1280   PetscCall(DMCreateLabel(dm, "Face Sets"));
1281   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
1282   if (markerSeparate) {
1283     markerBottom = faceMarkerBottom;
1284     markerTop    = faceMarkerTop;
1285     markerRight  = faceMarkerRight;
1286     markerLeft   = faceMarkerLeft;
1287   }
1288   {
1289     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
1290     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
1291     const PetscInt numZEdges    = rank == 0 ? 4 * edges[0] * edges[1] : 0; /* Z-edges are the 4 internal edges per cell */
1292     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC ? edges[0] : edges[0] + 1) : 0;
1293     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC ? edges[1] : edges[1] + 1) : 0;
1294     const PetscInt numZVertices = rank == 0 ? edges[0] * edges[1] : 0;
1295     const PetscInt numCells     = 4 * numXEdges * numYEdges;
1296     const PetscInt numTotXEdges = numXEdges * numYVertices;
1297     const PetscInt numTotYEdges = numYEdges * numXVertices;
1298     const PetscInt numVertices  = numXVertices * numYVertices + numZVertices;
1299     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numZEdges;
1300     const PetscInt firstVertex  = numCells;
1301     const PetscInt firstXEdge   = numCells + numVertices;
1302     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
1303     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
1304     Vec            coordinates;
1305     PetscSection   coordSection;
1306     PetscScalar   *coords;
1307     PetscInt       coordSize;
1308     PetscInt       v, vx, vy;
1309     PetscInt       c, e, ex, ey;
1310 
1311     PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVertices));
1312     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 3));
1313     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
1314     PetscCall(DMSetUp(dm));
1315 
1316     /* Build cells and Z-edges */
1317     for (ey = 0; ey < numYEdges; ++ey) {
1318       for (ex = 0; ex < numXEdges; ++ex) {
1319         const PetscInt exp1 = (ex + 1) % numXVertices;
1320         const PetscInt eyp1 = (ey + 1) % numYVertices;
1321         const PetscInt ez   = firstZEdge + 4 * (ey * numXEdges + ex);
1322         const PetscInt vc   = firstVertex + numXVertices * numYVertices + ey * numXEdges + ex;
1323         const PetscInt v0   = firstVertex + ey * numXVertices + ex;
1324         const PetscInt v1   = firstVertex + ey * numXVertices + exp1;
1325         const PetscInt v2   = firstVertex + eyp1 * numXVertices + exp1;
1326         const PetscInt v3   = firstVertex + eyp1 * numXVertices + ex;
1327         const PetscInt e0   = firstXEdge + ey * numXEdges + ex;
1328         const PetscInt e1   = firstYEdge + exp1 * numYEdges + ey;
1329         const PetscInt e2   = firstXEdge + eyp1 * numXEdges + ex;
1330         const PetscInt e3   = firstYEdge + ex * numYEdges + ey;
1331 
1332         const PetscInt cones[] = {ez, e0, ez + 1, ez + 1, e1, ez + 2, ez + 2, e2, ez + 3, ez + 3, e3, ez};
1333         const PetscInt ornts[] = {-1, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0};
1334         const PetscInt verts[] = {v0, vc, v1, vc, v2, vc, v3, vc};
1335 
1336         for (c = 0; c < 4; c++) {
1337           PetscInt cell = 4 * (ey * numXEdges + ex) + c;
1338           PetscInt edge = ez + c;
1339 
1340           PetscCall(DMPlexSetCone(dm, cell, cones + 3 * c));
1341           PetscCall(DMPlexSetConeOrientation(dm, cell, ornts + 3 * c));
1342           PetscCall(DMPlexSetCone(dm, edge, verts + 2 * c));
1343         }
1344       }
1345     }
1346 
1347     /* Build Y edges*/
1348     for (vx = 0; vx < numXVertices; vx++) {
1349       for (ey = 0; ey < numYEdges; ey++) {
1350         const PetscInt edge   = firstYEdge + vx * numYEdges + ey;
1351         const PetscInt v0     = firstVertex + ey * numXVertices + vx;
1352         const PetscInt v1     = firstVertex + ((ey + 1) % numYVertices) * numXVertices + vx;
1353         const PetscInt cone[] = {v0, v1};
1354 
1355         PetscCall(DMPlexSetCone(dm, edge, cone));
1356         if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
1357           if (vx == numXVertices - 1) {
1358             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
1359             PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1360             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1361             if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1362           } else if (vx == 0) {
1363             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
1364             PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1365             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1366             if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1367           }
1368         }
1369       }
1370     }
1371 
1372     /* Build X edges*/
1373     for (vy = 0; vy < numYVertices; vy++) {
1374       for (ex = 0; ex < numXEdges; ex++) {
1375         const PetscInt edge   = firstXEdge + vy * numXEdges + ex;
1376         const PetscInt v0     = firstVertex + vy * numXVertices + ex;
1377         const PetscInt v1     = firstVertex + vy * numXVertices + (ex + 1) % numXVertices;
1378         const PetscInt cone[] = {v0, v1};
1379 
1380         PetscCall(DMPlexSetCone(dm, edge, cone));
1381         if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
1382           if (vy == numYVertices - 1) {
1383             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
1384             PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1385             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1386             if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1387           } else if (vy == 0) {
1388             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
1389             PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1390             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1391             if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1392           }
1393         }
1394       }
1395     }
1396 
1397     /* Compute support, stratify, and celltype label */
1398     PetscCall(DMPlexSymmetrize(dm));
1399     PetscCall(DMPlexStratify(dm));
1400     PetscCall(DMPlexComputeCellTypes(dm));
1401 
1402     /* Build coordinates */
1403     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1404     PetscCall(PetscSectionSetNumFields(coordSection, 1));
1405     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
1406     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
1407     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
1408       PetscCall(PetscSectionSetDof(coordSection, v, 2));
1409       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
1410     }
1411     PetscCall(PetscSectionSetUp(coordSection));
1412     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1413     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1414     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1415     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1416     PetscCall(VecSetBlockSize(coordinates, 2));
1417     PetscCall(VecSetType(coordinates, VECSTANDARD));
1418     PetscCall(VecGetArray(coordinates, &coords));
1419     for (vy = 0; vy < numYVertices; ++vy) {
1420       for (vx = 0; vx < numXVertices; ++vx) {
1421         coords[2 * (vy * numXVertices + vx) + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
1422         coords[2 * (vy * numXVertices + vx) + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1423       }
1424     }
1425     for (ey = 0; ey < numYEdges; ++ey) {
1426       for (ex = 0; ex < numXEdges; ++ex) {
1427         const PetscInt c = ey * numXEdges + ex + numYVertices * numXVertices;
1428 
1429         coords[2 * c + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * (ex + 0.5);
1430         coords[2 * c + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * (ey + 0.5);
1431       }
1432     }
1433     PetscCall(VecRestoreArray(coordinates, &coords));
1434     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1435     PetscCall(VecDestroy(&coordinates));
1436 
1437     /* handle periodic BC */
1438     if (bdX == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_PERIODIC) {
1439       PetscReal L[2]       = {-1., -1.};
1440       PetscReal maxCell[2] = {-1., -1.};
1441 
1442       for (PetscInt d = 0; d < 2; ++d) {
1443         if (bd[d] != DM_BOUNDARY_NONE) {
1444           L[d]       = upper[d] - lower[d];
1445           maxCell[d] = 1.1 * (L[d] / PetscMax(1, edges[d]));
1446         }
1447       }
1448       PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1449     }
1450   }
1451   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1452   PetscFunctionReturn(PETSC_SUCCESS);
1453 }
1454 
DMPlexCreateBoxMesh_Simplex_Internal(DM dm,PetscInt dim,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType periodicity[],PetscBool interpolate)1455 static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
1456 {
1457   DM        boundary, vol;
1458   DMLabel   bdlabel;
1459   PetscBool crisscross = PETSC_FALSE;
1460 
1461   PetscFunctionBegin;
1462   PetscAssertPointer(dm, 1);
1463   if (dim == 2) PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_box_crisscross", &crisscross, NULL));
1464   if (crisscross) {
1465     PetscCall(DMPlexCreateSquareMesh_Simplex_CrissCross(dm, faces, lower, upper, periodicity));
1466   } else {
1467     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");
1468     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary));
1469     PetscCall(DMSetType(boundary, DMPLEX));
1470     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)boundary, ((PetscObject)dm)->prefix));
1471     PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE));
1472     PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol));
1473     PetscCall(DMGetLabel(vol, "marker", &bdlabel));
1474     if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel));
1475     PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol));
1476     PetscCall(DMPlexReplace_Internal(dm, &vol));
1477     PetscCall(DMDestroy(&boundary));
1478   }
1479   if (interpolate) {
1480     PetscCall(DMPlexInterpolateInPlace_Internal(dm));
1481     PetscCall(DMPlexSetBoxLabel_Internal(dm, periodicity));
1482   }
1483   PetscFunctionReturn(PETSC_SUCCESS);
1484 }
1485 
DMPlexCreateCubeMesh_Internal(DM dm,const PetscReal lower[],const PetscReal upper[],const PetscInt edges[],DMBoundaryType bdX,DMBoundaryType bdY,DMBoundaryType bdZ)1486 static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
1487 {
1488   DMLabel     cutLabel  = NULL;
1489   PetscInt    markerTop = 1, faceMarkerTop = 1;
1490   PetscInt    markerBottom = 1, faceMarkerBottom = 1;
1491   PetscInt    markerFront = 1, faceMarkerFront = 1;
1492   PetscInt    markerBack = 1, faceMarkerBack = 1;
1493   PetscInt    markerRight = 1, faceMarkerRight = 1;
1494   PetscInt    markerLeft = 1, faceMarkerLeft = 1;
1495   PetscInt    dim;
1496   PetscBool   markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
1497   PetscMPIInt rank;
1498 
1499   PetscFunctionBegin;
1500   PetscCall(DMGetDimension(dm, &dim));
1501   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1502   PetscCall(DMCreateLabel(dm, "marker"));
1503   PetscCall(DMCreateLabel(dm, "Face Sets"));
1504   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
1505   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) {
1506     if (cutMarker) {
1507       PetscCall(DMCreateLabel(dm, "periodic_cut"));
1508       PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
1509     }
1510   }
1511   switch (dim) {
1512   case 2:
1513     faceMarkerTop    = 3;
1514     faceMarkerBottom = 1;
1515     faceMarkerRight  = 2;
1516     faceMarkerLeft   = 4;
1517     break;
1518   case 3:
1519     faceMarkerBottom = 1;
1520     faceMarkerTop    = 2;
1521     faceMarkerFront  = 3;
1522     faceMarkerBack   = 4;
1523     faceMarkerRight  = 5;
1524     faceMarkerLeft   = 6;
1525     break;
1526   default:
1527     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
1528   }
1529   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
1530   if (markerSeparate) {
1531     markerBottom = faceMarkerBottom;
1532     markerTop    = faceMarkerTop;
1533     markerFront  = faceMarkerFront;
1534     markerBack   = faceMarkerBack;
1535     markerRight  = faceMarkerRight;
1536     markerLeft   = faceMarkerLeft;
1537   }
1538   {
1539     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
1540     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
1541     const PetscInt numZEdges    = rank == 0 ? edges[2] : 0;
1542     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0;
1543     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0;
1544     const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0;
1545     const PetscInt numCells     = numXEdges * numYEdges * numZEdges;
1546     const PetscInt numXFaces    = numYEdges * numZEdges;
1547     const PetscInt numYFaces    = numXEdges * numZEdges;
1548     const PetscInt numZFaces    = numXEdges * numYEdges;
1549     const PetscInt numTotXFaces = numXVertices * numXFaces;
1550     const PetscInt numTotYFaces = numYVertices * numYFaces;
1551     const PetscInt numTotZFaces = numZVertices * numZFaces;
1552     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
1553     const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices;
1554     const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices;
1555     const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices;
1556     const PetscInt numVertices  = numXVertices * numYVertices * numZVertices;
1557     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
1558     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
1559     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
1560     const PetscInt firstYFace   = firstXFace + numTotXFaces;
1561     const PetscInt firstZFace   = firstYFace + numTotYFaces;
1562     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
1563     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
1564     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
1565     Vec            coordinates;
1566     PetscSection   coordSection;
1567     PetscScalar   *coords;
1568     PetscInt       coordSize;
1569     PetscInt       v, vx, vy, vz;
1570     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;
1571 
1572     PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices));
1573     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
1574     for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
1575     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
1576     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
1577     /* Build cells */
1578     for (fz = 0; fz < numZEdges; ++fz) {
1579       for (fy = 0; fy < numYEdges; ++fy) {
1580         for (fx = 0; fx < numXEdges; ++fx) {
1581           PetscInt cell  = (fz * numYEdges + fy) * numXEdges + fx;
1582           PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
1583           PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices);
1584           PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
1585           PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices);
1586           PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
1587           PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices);
1588           /* B,  T,  F,  K,  R,  L */
1589           PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */
1590           PetscInt cone[6];
1591 
1592           /* no boundary twisting in 3D */
1593           cone[0] = faceB;
1594           cone[1] = faceT;
1595           cone[2] = faceF;
1596           cone[3] = faceK;
1597           cone[4] = faceR;
1598           cone[5] = faceL;
1599           PetscCall(DMPlexSetCone(dm, cell, cone));
1600           PetscCall(DMPlexSetConeOrientation(dm, cell, ornt));
1601           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
1602           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
1603           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
1604         }
1605       }
1606     }
1607     /* Build x faces */
1608     for (fz = 0; fz < numZEdges; ++fz) {
1609       for (fy = 0; fy < numYEdges; ++fy) {
1610         for (fx = 0; fx < numXVertices; ++fx) {
1611           PetscInt face    = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
1612           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
1613           PetscInt edgeR   = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz;
1614           PetscInt edgeB   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
1615           PetscInt edgeT   = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy;
1616           PetscInt ornt[4] = {0, 0, -1, -1};
1617           PetscInt cone[4];
1618 
1619           if (dim == 3) {
1620             /* markers */
1621             if (bdX != DM_BOUNDARY_PERIODIC) {
1622               if (fx == numXVertices - 1) {
1623                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight));
1624                 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight));
1625               } else if (fx == 0) {
1626                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft));
1627                 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft));
1628               }
1629             }
1630           }
1631           cone[0] = edgeB;
1632           cone[1] = edgeR;
1633           cone[2] = edgeT;
1634           cone[3] = edgeL;
1635           PetscCall(DMPlexSetCone(dm, face, cone));
1636           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1637         }
1638       }
1639     }
1640     /* Build y faces */
1641     for (fz = 0; fz < numZEdges; ++fz) {
1642       for (fx = 0; fx < numXEdges; ++fx) {
1643         for (fy = 0; fy < numYVertices; ++fy) {
1644           PetscInt face    = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
1645           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
1646           PetscInt edgeR   = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz;
1647           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1648           PetscInt edgeT   = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx;
1649           PetscInt ornt[4] = {0, 0, -1, -1};
1650           PetscInt cone[4];
1651 
1652           if (dim == 3) {
1653             /* markers */
1654             if (bdY != DM_BOUNDARY_PERIODIC) {
1655               if (fy == numYVertices - 1) {
1656                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack));
1657                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack));
1658               } else if (fy == 0) {
1659                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront));
1660                 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront));
1661               }
1662             }
1663           }
1664           cone[0] = edgeB;
1665           cone[1] = edgeR;
1666           cone[2] = edgeT;
1667           cone[3] = edgeL;
1668           PetscCall(DMPlexSetCone(dm, face, cone));
1669           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1670         }
1671       }
1672     }
1673     /* Build z faces */
1674     for (fy = 0; fy < numYEdges; ++fy) {
1675       for (fx = 0; fx < numXEdges; ++fx) {
1676         for (fz = 0; fz < numZVertices; fz++) {
1677           PetscInt face    = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
1678           PetscInt edgeL   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
1679           PetscInt edgeR   = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy;
1680           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1681           PetscInt edgeT   = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx;
1682           PetscInt ornt[4] = {0, 0, -1, -1};
1683           PetscInt cone[4];
1684 
1685           if (dim == 2) {
1686             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) {
1687               edgeR += numYEdges - 1 - 2 * fy;
1688               ornt[1] = -1;
1689             }
1690             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) {
1691               edgeT += numXEdges - 1 - 2 * fx;
1692               ornt[2] = 0;
1693             }
1694             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1695             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1696           } else {
1697             /* markers */
1698             if (bdZ != DM_BOUNDARY_PERIODIC) {
1699               if (fz == numZVertices - 1) {
1700                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop));
1701                 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop));
1702               } else if (fz == 0) {
1703                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom));
1704                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom));
1705               }
1706             }
1707           }
1708           cone[0] = edgeB;
1709           cone[1] = edgeR;
1710           cone[2] = edgeT;
1711           cone[3] = edgeL;
1712           PetscCall(DMPlexSetCone(dm, face, cone));
1713           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1714         }
1715       }
1716     }
1717     /* Build Z edges*/
1718     for (vy = 0; vy < numYVertices; vy++) {
1719       for (vx = 0; vx < numXVertices; vx++) {
1720         for (ez = 0; ez < numZEdges; ez++) {
1721           const PetscInt edge    = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez;
1722           const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx;
1723           const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx;
1724           PetscInt       cone[2];
1725 
1726           cone[0] = vertexB;
1727           cone[1] = vertexT;
1728           PetscCall(DMPlexSetCone(dm, edge, cone));
1729           if (dim == 3) {
1730             if (bdX != DM_BOUNDARY_PERIODIC) {
1731               if (vx == numXVertices - 1) {
1732                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1733                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1734                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1735               } else if (vx == 0) {
1736                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1737                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1738                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1739               }
1740             }
1741             if (bdY != DM_BOUNDARY_PERIODIC) {
1742               if (vy == numYVertices - 1) {
1743                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1744                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1745                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1746               } else if (vy == 0) {
1747                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1748                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1749                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1750               }
1751             }
1752           }
1753         }
1754       }
1755     }
1756     /* Build Y edges*/
1757     for (vz = 0; vz < numZVertices; vz++) {
1758       for (vx = 0; vx < numXVertices; vx++) {
1759         for (ey = 0; ey < numYEdges; ey++) {
1760           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx;
1761           const PetscInt edge    = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey;
1762           const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx;
1763           const PetscInt vertexK = firstVertex + nextv;
1764           PetscInt       cone[2];
1765 
1766           cone[0] = vertexF;
1767           cone[1] = vertexK;
1768           PetscCall(DMPlexSetCone(dm, edge, cone));
1769           if (dim == 2) {
1770             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
1771               if (vx == numXVertices - 1) {
1772                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
1773                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1774                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1775                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1776               } else if (vx == 0) {
1777                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
1778                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1779                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1780                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1781               }
1782             } else {
1783               if (vx == 0 && cutLabel) {
1784                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1785                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1786                 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1787               }
1788             }
1789           } else {
1790             if (bdX != DM_BOUNDARY_PERIODIC) {
1791               if (vx == numXVertices - 1) {
1792                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1793                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1794                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1795               } else if (vx == 0) {
1796                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1797                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1798                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1799               }
1800             }
1801             if (bdZ != DM_BOUNDARY_PERIODIC) {
1802               if (vz == numZVertices - 1) {
1803                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1804                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1805                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1806               } else if (vz == 0) {
1807                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1808                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1809                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1810               }
1811             }
1812           }
1813         }
1814       }
1815     }
1816     /* Build X edges*/
1817     for (vz = 0; vz < numZVertices; vz++) {
1818       for (vy = 0; vy < numYVertices; vy++) {
1819         for (ex = 0; ex < numXEdges; ex++) {
1820           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices;
1821           const PetscInt edge    = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex;
1822           const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex;
1823           const PetscInt vertexR = firstVertex + nextv;
1824           PetscInt       cone[2];
1825 
1826           cone[0] = vertexL;
1827           cone[1] = vertexR;
1828           PetscCall(DMPlexSetCone(dm, edge, cone));
1829           if (dim == 2) {
1830             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
1831               if (vy == numYVertices - 1) {
1832                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
1833                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1834                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1835                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1836               } else if (vy == 0) {
1837                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
1838                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1839                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1840                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1841               }
1842             } else {
1843               if (vy == 0 && cutLabel) {
1844                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1845                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1846                 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1847               }
1848             }
1849           } else {
1850             if (bdY != DM_BOUNDARY_PERIODIC) {
1851               if (vy == numYVertices - 1) {
1852                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1853                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1854                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1855               } else if (vy == 0) {
1856                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1857                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1858                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1859               }
1860             }
1861             if (bdZ != DM_BOUNDARY_PERIODIC) {
1862               if (vz == numZVertices - 1) {
1863                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1864                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1865                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1866               } else if (vz == 0) {
1867                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1868                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1869                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1870               }
1871             }
1872           }
1873         }
1874       }
1875     }
1876     PetscCall(DMPlexSymmetrize(dm));
1877     PetscCall(DMPlexStratify(dm));
1878     /* Build coordinates */
1879     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1880     PetscCall(PetscSectionSetNumFields(coordSection, 1));
1881     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1882     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
1883     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
1884       PetscCall(PetscSectionSetDof(coordSection, v, dim));
1885       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1886     }
1887     PetscCall(PetscSectionSetUp(coordSection));
1888     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1889     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1890     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1891     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1892     PetscCall(VecSetBlockSize(coordinates, dim));
1893     PetscCall(VecSetType(coordinates, VECSTANDARD));
1894     PetscCall(VecGetArray(coordinates, &coords));
1895     for (vz = 0; vz < numZVertices; ++vz) {
1896       for (vy = 0; vy < numYVertices; ++vy) {
1897         for (vx = 0; vx < numXVertices; ++vx) {
1898           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
1899           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1900           if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz;
1901         }
1902       }
1903     }
1904     PetscCall(VecRestoreArray(coordinates, &coords));
1905     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1906     PetscCall(VecDestroy(&coordinates));
1907   }
1908   PetscFunctionReturn(PETSC_SUCCESS);
1909 }
1910 
DMPlexCreateBoxMesh_Tensor_Internal(DM dm,PetscInt dim,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType periodicity[])1911 static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1912 {
1913   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1914   PetscInt       fac[3] = {0, 0, 0}, d;
1915 
1916   PetscFunctionBegin;
1917   PetscAssertPointer(dm, 1);
1918   PetscValidLogicalCollectiveInt(dm, dim, 2);
1919   PetscCall(DMSetDimension(dm, dim));
1920   for (d = 0; d < dim; ++d) {
1921     fac[d] = faces[d];
1922     bdt[d] = periodicity[d];
1923   }
1924   PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2]));
1925   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))) {
1926     PetscReal L[3]       = {-1., -1., 0.};
1927     PetscReal maxCell[3] = {-1., -1., 0.};
1928 
1929     for (d = 0; d < dim; ++d) {
1930       if (periodicity[d] != DM_BOUNDARY_NONE) {
1931         L[d]       = upper[d] - lower[d];
1932         maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d]));
1933       }
1934     }
1935     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1936   }
1937   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1938   PetscFunctionReturn(PETSC_SUCCESS);
1939 }
1940 
DMPlexCreateBoxMesh_Internal(DM dm,DMPlexShape shape,PetscInt dim,PetscBool simplex,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType periodicity[],PetscBool interpolate)1941 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)
1942 {
1943   PetscFunctionBegin;
1944   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1945   if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1946   else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0]));
1947   else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1948   else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity));
1949   if (!interpolate && dim > 1 && !simplex) {
1950     DM udm;
1951 
1952     PetscCall(DMPlexUninterpolate(dm, &udm));
1953     PetscCall(DMPlexCopyCoordinates(dm, udm));
1954     PetscCall(DMPlexReplace_Internal(dm, &udm));
1955   }
1956   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
1957   PetscFunctionReturn(PETSC_SUCCESS);
1958 }
1959 
1960 /*@
1961   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra).
1962 
1963   Collective
1964 
1965   Input Parameters:
1966 + comm               - The communicator for the `DM` object
1967 . dim                - The spatial dimension
1968 . simplex            - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells
1969 . faces              - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1970 . lower              - The lower left corner, or `NULL` for (0, 0, 0)
1971 . upper              - The upper right corner, or `NULL` for (1, 1, 1)
1972 . periodicity        - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
1973 . interpolate        - Flag to create intermediate mesh pieces (edges, faces)
1974 . localizationHeight - Flag to localize edges and faces in addition to cells; only significant for periodic meshes
1975 - sparseLocalize     - Flag to localize coordinates only for cells near the periodic boundary; only significant for periodic meshes
1976 
1977   Output Parameter:
1978 . dm - The `DM` object
1979 
1980   Level: beginner
1981 
1982   Note:
1983   To customize this mesh using options, use
1984 .vb
1985   DMCreate(comm, &dm);
1986   DMSetType(dm, DMPLEX);
1987   DMSetFromOptions(dm);
1988 .ve
1989   and use the options in `DMSetFromOptions()`.
1990 
1991   Here is the numbering returned for 2 faces in each direction for tensor cells\:
1992 .vb
1993  10---17---11---18----12
1994   |         |         |
1995   |         |         |
1996  20    2   22    3    24
1997   |         |         |
1998   |         |         |
1999   7---15----8---16----9
2000   |         |         |
2001   |         |         |
2002  19    0   21    1   23
2003   |         |         |
2004   |         |         |
2005   4---13----5---14----6
2006 .ve
2007   and for simplicial cells
2008 .vb
2009  14----8---15----9----16
2010   |\     5  |\      7 |
2011   | \       | \       |
2012  13   2    14    3    15
2013   | 4   \   | 6   \   |
2014   |       \ |       \ |
2015  11----6---12----7----13
2016   |\        |\        |
2017   | \    1  | \     3 |
2018  10   0    11    1    12
2019   | 0   \   | 2   \   |
2020   |       \ |       \ |
2021   8----4----9----5----10
2022 .ve
2023 
2024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
2025 @*/
DMPlexCreateBoxMesh(MPI_Comm comm,PetscInt dim,PetscBool simplex,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType periodicity[],PetscBool interpolate,PetscInt localizationHeight,PetscBool sparseLocalize,DM * dm)2026 PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, PetscInt localizationHeight, PetscBool sparseLocalize, DM *dm)
2027 {
2028   PetscInt       fac[3] = {1, 1, 1};
2029   PetscReal      low[3] = {0, 0, 0};
2030   PetscReal      upp[3] = {1, 1, 1};
2031   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
2032 
2033   PetscFunctionBegin;
2034   PetscCall(DMCreate(comm, dm));
2035   PetscCall(DMSetType(*dm, DMPLEX));
2036   PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate));
2037   if (periodicity) {
2038     DM cdm;
2039 
2040     PetscCall(DMGetCoordinateDM(*dm, &cdm));
2041     PetscCall(DMPlexSetMaxProjectionHeight(cdm, localizationHeight));
2042     PetscCall(DMSetSparseLocalize(*dm, sparseLocalize));
2043     PetscCall(DMLocalizeCoordinates(*dm));
2044   }
2045   PetscFunctionReturn(PETSC_SUCCESS);
2046 }
2047 
DMPlexCreateWedgeBoxMesh_Internal(DM dm,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType periodicity[])2048 static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
2049 {
2050   DM       bdm, vol;
2051   PetscInt i;
2052 
2053   PetscFunctionBegin;
2054   // TODO Now we can support periodicity
2055   for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported");
2056   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm));
2057   PetscCall(DMSetType(bdm, DMPLEX));
2058   PetscCall(DMSetDimension(bdm, 2));
2059   PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0));
2060   PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE));
2061   PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, NULL, &vol));
2062   PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0));
2063   PetscCall(DMDestroy(&bdm));
2064   PetscCall(DMPlexReplace_Internal(dm, &vol));
2065   if (lower[2] != 0.0) {
2066     Vec          v;
2067     PetscScalar *x;
2068     PetscInt     cDim, n;
2069 
2070     PetscCall(DMGetCoordinatesLocal(dm, &v));
2071     PetscCall(VecGetBlockSize(v, &cDim));
2072     PetscCall(VecGetLocalSize(v, &n));
2073     PetscCall(VecGetArray(v, &x));
2074     x += cDim;
2075     for (i = 0; i < n; i += cDim) x[i] += lower[2];
2076     PetscCall(VecRestoreArray(v, &x));
2077     PetscCall(DMSetCoordinatesLocal(dm, v));
2078   }
2079   PetscFunctionReturn(PETSC_SUCCESS);
2080 }
2081 
2082 /*@
2083   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tessellating the (x,y) plane and extruding in the third direction using wedge cells.
2084 
2085   Collective
2086 
2087   Input Parameters:
2088 + comm        - The communicator for the `DM` object
2089 . faces       - Number of faces per dimension, or `NULL` for (1, 1, 1)
2090 . lower       - The lower left corner, or `NULL` for (0, 0, 0)
2091 . upper       - The upper right corner, or `NULL` for (1, 1, 1)
2092 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
2093 . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
2094 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
2095 
2096   Output Parameter:
2097 . dm - The `DM` object
2098 
2099   Level: beginner
2100 
2101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2102 @*/
DMPlexCreateWedgeBoxMesh(MPI_Comm comm,const PetscInt faces[],const PetscReal lower[],const PetscReal upper[],const DMBoundaryType periodicity[],PetscBool orderHeight,PetscBool interpolate,DM * dm)2103 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm)
2104 {
2105   PetscInt       fac[3] = {1, 1, 1};
2106   PetscReal      low[3] = {0, 0, 0};
2107   PetscReal      upp[3] = {1, 1, 1};
2108   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
2109 
2110   PetscFunctionBegin;
2111   PetscCall(DMCreate(comm, dm));
2112   PetscCall(DMSetType(*dm, DMPLEX));
2113   PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt));
2114   if (!interpolate) {
2115     DM udm;
2116 
2117     PetscCall(DMPlexUninterpolate(*dm, &udm));
2118     PetscCall(DMPlexReplace_Internal(*dm, &udm));
2119   }
2120   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
2121   PetscFunctionReturn(PETSC_SUCCESS);
2122 }
2123 
2124 /*
2125   DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension.
2126 
2127   Input Parameters:
2128 + len - The length of the tuple
2129 . max - The maximum for each dimension, so values are in [0, max)
2130 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
2131 
2132   Output Parameter:
2133 . tup - A tuple of `len` integers whose entries are at most `max`
2134 
2135   Level: developer
2136 
2137   Note:
2138   Ordering is lexicographic with lowest index as least significant in ordering.
2139   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}.
2140 
2141 .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal()
2142 */
DMPlexTensorPointLexicographic_Private(PetscInt len,const PetscInt max[],PetscInt tup[])2143 static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[])
2144 {
2145   PetscInt i;
2146 
2147   PetscFunctionBegin;
2148   for (i = 0; i < len; ++i) {
2149     if (tup[i] < max[i] - 1) {
2150       break;
2151     } else {
2152       tup[i] = 0;
2153     }
2154   }
2155   if (i == len) tup[i - 1] = max[i - 1];
2156   else ++tup[i];
2157   PetscFunctionReturn(PETSC_SUCCESS);
2158 }
2159 
TupleToIndex_Private(PetscInt len,const PetscInt max[],const PetscInt tup[])2160 static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[])
2161 {
2162   PetscInt idx = tup[len - 1];
2163 
2164   for (PetscInt i = len - 2; i >= 0; --i) {
2165     idx *= max[i];
2166     idx += tup[i];
2167   }
2168   return idx;
2169 }
2170 
IndexToTuple_Private(PetscInt len,const PetscInt max[],PetscInt idx,PetscInt tup[])2171 static void IndexToTuple_Private(PetscInt len, const PetscInt max[], PetscInt idx, PetscInt tup[])
2172 {
2173   for (PetscInt i = 0; i < len; ++i) {
2174     tup[i] = idx % max[i];
2175     idx    = (idx - tup[i]) / max[i];
2176   }
2177 }
2178 
TupleToRanks_Private(PetscInt len,const PetscInt max[],const PetscInt procs[],const PetscInt tup[],PetscInt ranks[])2179 static void TupleToRanks_Private(PetscInt len, const PetscInt max[], const PetscInt procs[], const PetscInt tup[], PetscInt ranks[])
2180 {
2181   for (PetscInt i = 0; i < len; ++i) {
2182     const PetscInt div = max[i] / procs[i];
2183     const PetscInt rem = max[i] % procs[i];
2184     const PetscInt idx = (tup[i] < 0 ? max[i] + tup[i] : tup[i]) % max[i];
2185 
2186     if (idx < rem * (div + 1)) ranks[i] = idx / (div + 1);
2187     else ranks[i] = rem + (idx - rem * (div + 1)) / div;
2188   }
2189 }
2190 
RanksToSizes_Private(PetscInt len,const PetscInt max[],const PetscInt procs[],const PetscInt ranks[],PetscInt sizes[])2191 static void RanksToSizes_Private(PetscInt len, const PetscInt max[], const PetscInt procs[], const PetscInt ranks[], PetscInt sizes[])
2192 {
2193   for (PetscInt i = 0; i < len; ++i) {
2194     const PetscInt div = max[i] / procs[i];
2195     const PetscInt rem = max[i] % procs[i];
2196 
2197     sizes[i] = ranks[i] < rem ? div + 1 : div;
2198   }
2199 }
2200 
2201 /*
2202   In serial, the mesh is completely periodic. In parallel, we will include a layer of ghost vertices around the patch, so our edges will not wrap around in parallel. This will instead be handled by the SF.
2203 
2204   The cone for all edges will always be complete. Even in the presence of boundaries, we will keep all support sizes constant. When an edge would not exist in the support, we will create one to wrap back periodically. This allows for uniform stencils, and that edge will not be used for computation.
2205 
2206   All point which do not attain the vertex lower or upper bound in any dimension are owned, the rest are leaves owned by another process and present in the SF.
2207 
2208   Parallel Layout:
2209 
2210   We create a cubic process grid of dimension P^{1/d} on each side. The IndexToTuple_Private() function maps the global rank to the local rank in each dimension. We divide edges using the PETSc distribution rule in each dimension, and then add overlap. TupleToRanks_Private() returns the local rank in ech dimension for a tuple. RanksToSizes_Private() gives the size in each dimension for the domain with those local ranks.
2211 */
DMPlexCreateHypercubicMesh_Internal(DM dm,PetscInt dim,const PetscReal lower[],const PetscReal upper[],const PetscInt edges[],PetscInt overlap,const DMBoundaryType bd[])2212 static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], PetscInt overlap, const DMBoundaryType bd[])
2213 {
2214   const PetscInt debug = ((DM_Plex *)dm->data)->printAdj;
2215   PetscSF        sf;
2216   Vec            coordinates;
2217   PetscSection   coordSection;
2218   DMLabel        cutLabel    = NULL;
2219   PetscBool      cutMarker   = PETSC_FALSE;
2220   PetscBool      periodic    = PETSC_FALSE;
2221   PetscInt       numCells    = 1;
2222   PetscInt       numVertices = 1;
2223   PetscSFNode   *remotes;
2224   PetscScalar   *coords;
2225   PetscInt      *procs;     // The number of processes along each dimension
2226   PetscInt      *lrank;     // Rank in each dimension, lrank[d] \in [0, procs[d])
2227   PetscInt      *ledges;    // The number of edges along each dimension for this process
2228   PetscInt      *vstart;    // The first vertex along each dimension on this processes
2229   PetscInt      *vertices;  // The number of vertices along each dimension on this process
2230   PetscInt      *rvert;     // The global (not local) vertex number along each dimension
2231   PetscInt      *rrank;     // The rank along each dimension for the process owning rvert[]
2232   PetscInt      *rvertices; // The number of vertices along each dimension for the process rrank[]
2233   PetscInt      *vert, *vtmp, *supp, cone[2], *leaves;
2234   PetscInt       cell = 0, coordSize, Nl = 0, Nl2 = 0;
2235   PetscMPIInt    rank, size;
2236   MPI_Comm       comm;
2237 
2238   PetscFunctionBegin;
2239   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2240   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2241   PetscCallMPI(MPI_Comm_size(comm, &size));
2242   PetscCall(DMSetDimension(dm, dim));
2243   PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
2244   PetscCall(PetscCalloc4(dim, &procs, dim, &lrank, dim, &rrank, 2 * dim, &supp));
2245   PetscCall(PetscCalloc7(dim, &ledges, dim, &vertices, dim, &rvertices, dim, &vert, dim, &rvert, dim, &vstart, dim, &vtmp));
2246   PetscCall(DMCreateLabel(dm, "marker"));
2247   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
2248   for (PetscInt d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE;
2249   if (periodic && cutMarker) {
2250     PetscCall(DMCreateLabel(dm, "periodic_cut"));
2251     PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
2252   }
2253   for (PetscInt d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, comm, PETSC_ERR_SUP, "Hypercubic mesh must be periodic now");
2254   overlap = overlap == PETSC_DETERMINE ? 1 : overlap;
2255   PetscCheck(overlap >= 1, comm, PETSC_ERR_SUP, "Overlap %" PetscInt_FMT " must be greater than 0", overlap);
2256   if (size > 1) {
2257     PetscInt Npr = 1;
2258 
2259     // Make process grid
2260     if (debug) PetscCall(PetscPrintf(comm, "Process grid:"));
2261     for (PetscInt d = 0; d < dim; ++d) {
2262       procs[d] = PetscRintReal(PetscPowReal(size, 1. / dim));
2263       Npr *= procs[d];
2264       if (debug) PetscCall(PetscPrintf(comm, " %" PetscInt_FMT, procs[d]));
2265     }
2266     if (debug) PetscCall(PetscPrintf(comm, "\n"));
2267     PetscCheck(Npr == size, comm, PETSC_ERR_PLIB, "Process grid size %" PetscInt_FMT " != %d comm size", Npr, size);
2268     IndexToTuple_Private(dim, procs, rank, lrank);
2269     for (PetscInt d = 0; d < dim; ++d) {
2270       ledges[d] = edges[d] / procs[d] + (edges[d] % procs[d] > lrank[d] ? 1 : 0);
2271       vstart[d] = 0;
2272       for (PetscInt r = 0; r < lrank[d]; ++r) vstart[d] += edges[d] / procs[d] + (edges[d] % procs[d] > r ? 1 : 0);
2273       vstart[d] -= overlap; // For halo
2274     }
2275   } else {
2276     for (PetscInt d = 0; d < dim; ++d) {
2277       procs[d]  = 1;
2278       ledges[d] = edges[d];
2279     }
2280   }
2281   // Calculate local patch size
2282   for (PetscInt d = 0; d < dim; ++d) {
2283     vertices[d] = ledges[d] + (procs[d] > 1 ? 2 * overlap : 0);
2284     numVertices *= vertices[d];
2285   }
2286   numCells = numVertices * dim;
2287   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
2288   for (PetscInt c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2));
2289   for (PetscInt v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim));
2290   PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */
2291   /* Build cell cones and vertex supports */
2292   PetscCall(DMCreateLabel(dm, "celltype"));
2293   if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Topology for rank %d:\n", rank));
2294   while (vert[dim - 1] < vertices[dim - 1]) {
2295     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells;
2296     PetscInt       s      = 0;
2297     PetscBool      leaf   = PETSC_FALSE;
2298 
2299     if (debug) {
2300       PetscCall(PetscSynchronizedPrintf(comm, "Vertex %" PetscInt_FMT ":", vertex));
2301       for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vert[d]));
2302       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
2303     }
2304     PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT));
2305     // Define edge cones
2306     for (PetscInt d = 0; d < dim; ++d) {
2307       for (PetscInt e = 0; e < dim; ++e) vtmp[e] = vert[e];
2308       vtmp[d] = (vert[d] + 1) % vertices[d];
2309       cone[0] = vertex;
2310       cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells;
2311       if (debug) {
2312         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ":", cone[1]));
2313         for (PetscInt e = 0; e < dim; ++e) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vtmp[e]));
2314         PetscCall(PetscSynchronizedPrintf(comm, "\n"));
2315       }
2316       PetscCall(DMPlexSetCone(dm, cell, cone));
2317       PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT));
2318       if (debug) PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1]));
2319       ++cell;
2320       // Shared vertices are any in the first or last overlap layers
2321       if (vert[d] < overlap || vert[d] >= vertices[d] - overlap) leaf = PETSC_TRUE;
2322     }
2323     if (size > 1 && leaf) ++Nl;
2324     // Define vertex supports
2325     for (PetscInt d = 0; d < dim; ++d) {
2326       for (PetscInt e = 0; e < dim; ++e) vtmp[e] = vert[e];
2327       vtmp[d]   = (vert[d] + vertices[d] - 1) % vertices[d];
2328       supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d;
2329       supp[s++] = (vertex - numCells) * dim + d;
2330       PetscCall(DMPlexSetSupport(dm, vertex, supp));
2331     }
2332     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
2333   }
2334   if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL));
2335   PetscCall(DMPlexStratify(dm));
2336   // Allocate for SF
2337   PetscCall(PetscMalloc1(Nl, &leaves));
2338   PetscCall(PetscMalloc1(Nl, &remotes));
2339   // Build coordinates
2340   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2341   PetscCall(PetscSectionSetNumFields(coordSection, 1));
2342   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2343   PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2344   for (PetscInt v = numCells; v < numCells + numVertices; ++v) {
2345     PetscCall(PetscSectionSetDof(coordSection, v, dim));
2346     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2347   }
2348   PetscCall(PetscSectionSetUp(coordSection));
2349   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2350   PetscCall(VecCreate(comm, &coordinates));
2351   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2352   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2353   PetscCall(VecSetBlockSize(coordinates, dim));
2354   PetscCall(VecSetType(coordinates, VECSTANDARD));
2355   PetscCall(VecGetArray(coordinates, &coords));
2356   if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Geometry for rank %d:\n", rank));
2357   for (PetscInt d = 0; d < dim; ++d) vert[d] = 0;
2358   while (vert[dim - 1] < vertices[dim - 1]) {
2359     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert);
2360     PetscBool      leaf   = PETSC_FALSE;
2361 
2362     for (PetscInt d = 0; d < dim; ++d) {
2363       coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / edges[d]) * (vert[d] + vstart[d]);
2364       if (vert[d] < overlap || vert[d] >= vertices[d] - overlap) leaf = PETSC_TRUE;
2365     }
2366     if (size > 1 && leaf) {
2367       PetscInt rnumCells = 1;
2368 
2369       for (PetscInt d = 0; d < dim; ++d) rvert[d] = vert[d] + vstart[d];
2370       TupleToRanks_Private(dim, edges, procs, rvert, rrank);
2371       leaves[Nl2]       = vertex + numCells;
2372       remotes[Nl2].rank = TupleToIndex_Private(dim, procs, rrank);
2373       RanksToSizes_Private(dim, edges, procs, rrank, rvertices);
2374       for (PetscInt d = 0; d < dim; ++d) {
2375         rvertices[d] += 2 * overlap; // Add halo
2376         rnumCells *= rvertices[d];
2377       }
2378       rnumCells *= dim;
2379       for (PetscInt d = 0; d < dim; ++d) {
2380         const PetscInt diff = rrank[d] - lrank[d];
2381 
2382         if (!diff) rvert[d] = vert[d];                                     // Vertex is local
2383         else if (rvert[d] < 0) rvert[d] = rvertices[d] - 1 + rvert[d];     // Wrap around at the bottom
2384         else if (rvert[d] >= edges[d]) rvert[d] = rvert[d] - edges[d] + 1; // Wrap around at the top
2385         else if (diff == -1) rvert[d] = rvertices[d] - 1 + (vert[d] - overlap);
2386         else if (diff == 1) rvert[d] = (vertices[d] - vert[d] - 1) + overlap;
2387         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Process distance %" PetscInt_FMT " in direction %" PetscInt_FMT " should not be possible", diff, d);
2388       }
2389       remotes[Nl2].index = TupleToIndex_Private(dim, rvertices, rvert) + rnumCells;
2390       if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Shared Vertex %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", leaves[Nl2], remotes[Nl2].rank, remotes[Nl2].index));
2391       ++Nl2;
2392     }
2393     if (debug) {
2394       PetscCall(PetscSynchronizedPrintf(comm, "Vertex %" PetscInt_FMT ":", vertex));
2395       for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vert[d] + vstart[d]));
2396       for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %g", (double)PetscRealPart(coords[vertex * dim + d])));
2397       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
2398     }
2399     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
2400   }
2401   if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL));
2402   PetscCall(VecRestoreArray(coordinates, &coords));
2403   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2404   PetscCall(VecDestroy(&coordinates));
2405   // Build SF
2406   PetscCheck(Nl == Nl2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Initial number of leaves %" PetscInt_FMT " != %" PetscInt_FMT " final number", Nl, Nl2);
2407   PetscCall(DMGetPointSF(dm, &sf));
2408   PetscCall(PetscSFSetGraph(sf, numCells + numVertices, Nl, leaves, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
2409   if (debug) PetscCall(PetscSFView(sf, PETSC_VIEWER_STDOUT_WORLD));
2410   //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper));
2411   // Attach the extent
2412   {
2413     PetscContainer c;
2414     PetscInt      *extent, *lextent;
2415 
2416     PetscCall(PetscMalloc1(dim, &extent));
2417     PetscCall(PetscMalloc1(dim, &lextent));
2418     for (PetscInt d = 0; d < dim; ++d) {
2419       extent[d]  = edges[d];
2420       lextent[d] = ledges[d];
2421     }
2422     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
2423     PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault));
2424     PetscCall(PetscContainerSetPointer(c, extent));
2425     PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c));
2426     PetscCall(PetscContainerDestroy(&c));
2427     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
2428     PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault));
2429     PetscCall(PetscContainerSetPointer(c, lextent));
2430     PetscCall(PetscObjectCompose((PetscObject)dm, "_lextent", (PetscObject)c));
2431     PetscCall(PetscContainerDestroy(&c));
2432   }
2433   PetscCall(PetscFree4(procs, lrank, rrank, supp));
2434   PetscCall(PetscFree7(ledges, vertices, rvertices, vert, rvert, vstart, vtmp));
2435   PetscFunctionReturn(PETSC_SUCCESS);
2436 }
2437 
2438 /*@C
2439   DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges.
2440 
2441   Collective
2442 
2443   Input Parameters:
2444 + comm    - The communicator for the `DM` object
2445 . dim     - The spatial dimension
2446 . edges   - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
2447 . lower   - The lower left corner, or `NULL` for (0, 0, 0)
2448 . upper   - The upper right corner, or `NULL` for (1, 1, 1)
2449 - overlap - The number of vertices in each direction to include in the overlap (default is 1)
2450 
2451   Output Parameter:
2452 . dm - The DM object
2453 
2454   Level: beginner
2455 
2456   Note:
2457   If you want to customize this mesh using options, you just need to
2458 .vb
2459   DMCreate(comm, &dm);
2460   DMSetType(dm, DMPLEX);
2461   DMSetFromOptions(dm);
2462 .ve
2463   and use the options on the `DMSetFromOptions()` page.
2464 
2465   The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively,
2466 .vb
2467  18--0-19--2-20--4-18
2468   |     |     |     |
2469  13    15    17    13
2470   |     |     |     |
2471  24-12-25-14-26-16-24
2472   |     |     |     |
2473   7     9    11     7
2474   |     |     |     |
2475  21--6-22--8-23-10-21
2476   |     |     |     |
2477   1     3     5     1
2478   |     |     |     |
2479  18--0-19--2-20--4-18
2480 .ve
2481 
2482 .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
2483 @*/
DMPlexCreateHypercubicMesh(MPI_Comm comm,PetscInt dim,const PetscInt edges[],const PetscReal lower[],const PetscReal upper[],PetscInt overlap,DM * dm)2484 PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], PetscInt overlap, DM *dm)
2485 {
2486   PetscInt       *edg;
2487   PetscReal      *low, *upp;
2488   DMBoundaryType *bdt;
2489   PetscInt        d;
2490 
2491   PetscFunctionBegin;
2492   PetscCall(DMCreate(comm, dm));
2493   PetscCall(DMSetType(*dm, DMPLEX));
2494   PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt));
2495   for (d = 0; d < dim; ++d) {
2496     edg[d] = edges ? edges[d] : 1;
2497     low[d] = lower ? lower[d] : 0.;
2498     upp[d] = upper ? upper[d] : 1.;
2499     bdt[d] = DM_BOUNDARY_PERIODIC;
2500   }
2501   PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, overlap, bdt));
2502   PetscCall(PetscFree4(edg, low, upp, bdt));
2503   PetscFunctionReturn(PETSC_SUCCESS);
2504 }
2505 
2506 /*@
2507   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database.
2508 
2509   Logically Collective
2510 
2511   Input Parameters:
2512 + dm     - the `DM` context
2513 - prefix - the prefix to prepend to all option names
2514 
2515   Level: advanced
2516 
2517   Note:
2518   A hyphen (-) must NOT be given at the beginning of the prefix name.
2519   The first character of all runtime options is AUTOMATICALLY the hyphen.
2520 
2521 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()`
2522 @*/
DMPlexSetOptionsPrefix(DM dm,const char prefix[])2523 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
2524 {
2525   DM_Plex *mesh = (DM_Plex *)dm->data;
2526 
2527   PetscFunctionBegin;
2528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2529   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
2530   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix));
2531   PetscFunctionReturn(PETSC_SUCCESS);
2532 }
2533 
2534 /* Remap geometry to cylinder
2535    TODO: This only works for a single refinement, then it is broken
2536 
2537      Interior square: Linear interpolation is correct
2538      The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
2539      such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance
2540 
2541        phi     = arctan(y/x)
2542        d_close = sqrt(1/8 + 1/4 sin^2(phi))
2543        d_far   = sqrt(1/2 + sin^2(phi))
2544 
2545      so we remap them using
2546 
2547        x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
2548        y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)
2549 
2550      If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
2551 */
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[])2552 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[])
2553 {
2554   const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
2555   const PetscReal ds2 = 0.5 * dis;
2556 
2557   if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) {
2558     f0[0] = u[0];
2559     f0[1] = u[1];
2560   } else {
2561     PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;
2562 
2563     x    = PetscRealPart(u[0]);
2564     y    = PetscRealPart(u[1]);
2565     phi  = PetscAtan2Real(y, x);
2566     sinp = PetscSinReal(phi);
2567     cosp = PetscCosReal(phi);
2568     if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) {
2569       dc = PetscAbsReal(ds2 / sinp);
2570       df = PetscAbsReal(dis / sinp);
2571       xc = ds2 * x / PetscAbsReal(y);
2572       yc = ds2 * PetscSignReal(y);
2573     } else {
2574       dc = PetscAbsReal(ds2 / cosp);
2575       df = PetscAbsReal(dis / cosp);
2576       xc = ds2 * PetscSignReal(x);
2577       yc = ds2 * y / PetscAbsReal(x);
2578     }
2579     f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc);
2580     f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc);
2581   }
2582   f0[2] = u[2];
2583 }
2584 
DMPlexCreateHexCylinderMesh_Internal(DM dm,DMBoundaryType periodicZ,PetscInt Nr)2585 static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ, PetscInt Nr)
2586 {
2587   const PetscInt dim = 3;
2588   PetscInt       numCells, numVertices;
2589   PetscMPIInt    rank;
2590 
2591   PetscFunctionBegin;
2592   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2593   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2594   PetscCall(DMSetDimension(dm, dim));
2595   /* Create topology */
2596   {
2597     PetscInt cone[8], c;
2598 
2599     numCells    = rank == 0 ? 5 : 0;
2600     numVertices = rank == 0 ? 16 : 0;
2601     if (periodicZ == DM_BOUNDARY_PERIODIC) {
2602       numCells *= 3;
2603       numVertices = rank == 0 ? 24 : 0;
2604     }
2605     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
2606     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8));
2607     PetscCall(DMSetUp(dm));
2608     if (rank == 0) {
2609       if (periodicZ == DM_BOUNDARY_PERIODIC) {
2610         cone[0] = 15;
2611         cone[1] = 18;
2612         cone[2] = 17;
2613         cone[3] = 16;
2614         cone[4] = 31;
2615         cone[5] = 32;
2616         cone[6] = 33;
2617         cone[7] = 34;
2618         PetscCall(DMPlexSetCone(dm, 0, cone));
2619         cone[0] = 16;
2620         cone[1] = 17;
2621         cone[2] = 24;
2622         cone[3] = 23;
2623         cone[4] = 32;
2624         cone[5] = 36;
2625         cone[6] = 37;
2626         cone[7] = 33; /* 22 25 26 21 */
2627         PetscCall(DMPlexSetCone(dm, 1, cone));
2628         cone[0] = 18;
2629         cone[1] = 27;
2630         cone[2] = 24;
2631         cone[3] = 17;
2632         cone[4] = 34;
2633         cone[5] = 33;
2634         cone[6] = 37;
2635         cone[7] = 38;
2636         PetscCall(DMPlexSetCone(dm, 2, cone));
2637         cone[0] = 29;
2638         cone[1] = 27;
2639         cone[2] = 18;
2640         cone[3] = 15;
2641         cone[4] = 35;
2642         cone[5] = 31;
2643         cone[6] = 34;
2644         cone[7] = 38;
2645         PetscCall(DMPlexSetCone(dm, 3, cone));
2646         cone[0] = 29;
2647         cone[1] = 15;
2648         cone[2] = 16;
2649         cone[3] = 23;
2650         cone[4] = 35;
2651         cone[5] = 36;
2652         cone[6] = 32;
2653         cone[7] = 31;
2654         PetscCall(DMPlexSetCone(dm, 4, cone));
2655 
2656         cone[0] = 31;
2657         cone[1] = 34;
2658         cone[2] = 33;
2659         cone[3] = 32;
2660         cone[4] = 19;
2661         cone[5] = 22;
2662         cone[6] = 21;
2663         cone[7] = 20;
2664         PetscCall(DMPlexSetCone(dm, 5, cone));
2665         cone[0] = 32;
2666         cone[1] = 33;
2667         cone[2] = 37;
2668         cone[3] = 36;
2669         cone[4] = 22;
2670         cone[5] = 25;
2671         cone[6] = 26;
2672         cone[7] = 21;
2673         PetscCall(DMPlexSetCone(dm, 6, cone));
2674         cone[0] = 34;
2675         cone[1] = 38;
2676         cone[2] = 37;
2677         cone[3] = 33;
2678         cone[4] = 20;
2679         cone[5] = 21;
2680         cone[6] = 26;
2681         cone[7] = 28;
2682         PetscCall(DMPlexSetCone(dm, 7, cone));
2683         cone[0] = 35;
2684         cone[1] = 38;
2685         cone[2] = 34;
2686         cone[3] = 31;
2687         cone[4] = 30;
2688         cone[5] = 19;
2689         cone[6] = 20;
2690         cone[7] = 28;
2691         PetscCall(DMPlexSetCone(dm, 8, cone));
2692         cone[0] = 35;
2693         cone[1] = 31;
2694         cone[2] = 32;
2695         cone[3] = 36;
2696         cone[4] = 30;
2697         cone[5] = 25;
2698         cone[6] = 22;
2699         cone[7] = 19;
2700         PetscCall(DMPlexSetCone(dm, 9, cone));
2701 
2702         cone[0] = 19;
2703         cone[1] = 20;
2704         cone[2] = 21;
2705         cone[3] = 22;
2706         cone[4] = 15;
2707         cone[5] = 16;
2708         cone[6] = 17;
2709         cone[7] = 18;
2710         PetscCall(DMPlexSetCone(dm, 10, cone));
2711         cone[0] = 22;
2712         cone[1] = 21;
2713         cone[2] = 26;
2714         cone[3] = 25;
2715         cone[4] = 16;
2716         cone[5] = 23;
2717         cone[6] = 24;
2718         cone[7] = 17;
2719         PetscCall(DMPlexSetCone(dm, 11, cone));
2720         cone[0] = 20;
2721         cone[1] = 28;
2722         cone[2] = 26;
2723         cone[3] = 21;
2724         cone[4] = 18;
2725         cone[5] = 17;
2726         cone[6] = 24;
2727         cone[7] = 27;
2728         PetscCall(DMPlexSetCone(dm, 12, cone));
2729         cone[0] = 30;
2730         cone[1] = 28;
2731         cone[2] = 20;
2732         cone[3] = 19;
2733         cone[4] = 29;
2734         cone[5] = 15;
2735         cone[6] = 18;
2736         cone[7] = 27;
2737         PetscCall(DMPlexSetCone(dm, 13, cone));
2738         cone[0] = 30;
2739         cone[1] = 19;
2740         cone[2] = 22;
2741         cone[3] = 25;
2742         cone[4] = 29;
2743         cone[5] = 23;
2744         cone[6] = 16;
2745         cone[7] = 15;
2746         PetscCall(DMPlexSetCone(dm, 14, cone));
2747       } else {
2748         cone[0] = 5;
2749         cone[1] = 8;
2750         cone[2] = 7;
2751         cone[3] = 6;
2752         cone[4] = 9;
2753         cone[5] = 12;
2754         cone[6] = 11;
2755         cone[7] = 10;
2756         PetscCall(DMPlexSetCone(dm, 0, cone));
2757         cone[0] = 6;
2758         cone[1] = 7;
2759         cone[2] = 14;
2760         cone[3] = 13;
2761         cone[4] = 12;
2762         cone[5] = 15;
2763         cone[6] = 16;
2764         cone[7] = 11;
2765         PetscCall(DMPlexSetCone(dm, 1, cone));
2766         cone[0] = 8;
2767         cone[1] = 17;
2768         cone[2] = 14;
2769         cone[3] = 7;
2770         cone[4] = 10;
2771         cone[5] = 11;
2772         cone[6] = 16;
2773         cone[7] = 18;
2774         PetscCall(DMPlexSetCone(dm, 2, cone));
2775         cone[0] = 19;
2776         cone[1] = 17;
2777         cone[2] = 8;
2778         cone[3] = 5;
2779         cone[4] = 20;
2780         cone[5] = 9;
2781         cone[6] = 10;
2782         cone[7] = 18;
2783         PetscCall(DMPlexSetCone(dm, 3, cone));
2784         cone[0] = 19;
2785         cone[1] = 5;
2786         cone[2] = 6;
2787         cone[3] = 13;
2788         cone[4] = 20;
2789         cone[5] = 15;
2790         cone[6] = 12;
2791         cone[7] = 9;
2792         PetscCall(DMPlexSetCone(dm, 4, cone));
2793       }
2794     }
2795     PetscCall(DMPlexSymmetrize(dm));
2796     PetscCall(DMPlexStratify(dm));
2797   }
2798   /* Create cube geometry */
2799   {
2800     Vec             coordinates;
2801     PetscSection    coordSection;
2802     PetscScalar    *coords;
2803     PetscInt        coordSize, v;
2804     const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
2805     const PetscReal ds2 = dis / 2.0;
2806 
2807     /* Build coordinates */
2808     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2809     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2810     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2811     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2812     for (v = numCells; v < numCells + numVertices; ++v) {
2813       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2814       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2815     }
2816     PetscCall(PetscSectionSetUp(coordSection));
2817     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2818     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2819     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2820     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2821     PetscCall(VecSetBlockSize(coordinates, dim));
2822     PetscCall(VecSetType(coordinates, VECSTANDARD));
2823     PetscCall(VecGetArray(coordinates, &coords));
2824     if (rank == 0) {
2825       coords[0 * dim + 0]  = -ds2;
2826       coords[0 * dim + 1]  = -ds2;
2827       coords[0 * dim + 2]  = 0.0;
2828       coords[1 * dim + 0]  = ds2;
2829       coords[1 * dim + 1]  = -ds2;
2830       coords[1 * dim + 2]  = 0.0;
2831       coords[2 * dim + 0]  = ds2;
2832       coords[2 * dim + 1]  = ds2;
2833       coords[2 * dim + 2]  = 0.0;
2834       coords[3 * dim + 0]  = -ds2;
2835       coords[3 * dim + 1]  = ds2;
2836       coords[3 * dim + 2]  = 0.0;
2837       coords[4 * dim + 0]  = -ds2;
2838       coords[4 * dim + 1]  = -ds2;
2839       coords[4 * dim + 2]  = 1.0;
2840       coords[5 * dim + 0]  = -ds2;
2841       coords[5 * dim + 1]  = ds2;
2842       coords[5 * dim + 2]  = 1.0;
2843       coords[6 * dim + 0]  = ds2;
2844       coords[6 * dim + 1]  = ds2;
2845       coords[6 * dim + 2]  = 1.0;
2846       coords[7 * dim + 0]  = ds2;
2847       coords[7 * dim + 1]  = -ds2;
2848       coords[7 * dim + 2]  = 1.0;
2849       coords[8 * dim + 0]  = dis;
2850       coords[8 * dim + 1]  = -dis;
2851       coords[8 * dim + 2]  = 0.0;
2852       coords[9 * dim + 0]  = dis;
2853       coords[9 * dim + 1]  = dis;
2854       coords[9 * dim + 2]  = 0.0;
2855       coords[10 * dim + 0] = dis;
2856       coords[10 * dim + 1] = -dis;
2857       coords[10 * dim + 2] = 1.0;
2858       coords[11 * dim + 0] = dis;
2859       coords[11 * dim + 1] = dis;
2860       coords[11 * dim + 2] = 1.0;
2861       coords[12 * dim + 0] = -dis;
2862       coords[12 * dim + 1] = dis;
2863       coords[12 * dim + 2] = 0.0;
2864       coords[13 * dim + 0] = -dis;
2865       coords[13 * dim + 1] = dis;
2866       coords[13 * dim + 2] = 1.0;
2867       coords[14 * dim + 0] = -dis;
2868       coords[14 * dim + 1] = -dis;
2869       coords[14 * dim + 2] = 0.0;
2870       coords[15 * dim + 0] = -dis;
2871       coords[15 * dim + 1] = -dis;
2872       coords[15 * dim + 2] = 1.0;
2873       if (periodicZ == DM_BOUNDARY_PERIODIC) {
2874         /* 15 31 19 */ coords[16 * dim + 0] = -ds2;
2875         coords[16 * dim + 1]                = -ds2;
2876         coords[16 * dim + 2]                = 0.5;
2877         /* 16 32 22 */ coords[17 * dim + 0] = ds2;
2878         coords[17 * dim + 1]                = -ds2;
2879         coords[17 * dim + 2]                = 0.5;
2880         /* 17 33 21 */ coords[18 * dim + 0] = ds2;
2881         coords[18 * dim + 1]                = ds2;
2882         coords[18 * dim + 2]                = 0.5;
2883         /* 18 34 20 */ coords[19 * dim + 0] = -ds2;
2884         coords[19 * dim + 1]                = ds2;
2885         coords[19 * dim + 2]                = 0.5;
2886         /* 29 35 30 */ coords[20 * dim + 0] = -dis;
2887         coords[20 * dim + 1]                = -dis;
2888         coords[20 * dim + 2]                = 0.5;
2889         /* 23 36 25 */ coords[21 * dim + 0] = dis;
2890         coords[21 * dim + 1]                = -dis;
2891         coords[21 * dim + 2]                = 0.5;
2892         /* 24 37 26 */ coords[22 * dim + 0] = dis;
2893         coords[22 * dim + 1]                = dis;
2894         coords[22 * dim + 2]                = 0.5;
2895         /* 27 38 28 */ coords[23 * dim + 0] = -dis;
2896         coords[23 * dim + 1]                = dis;
2897         coords[23 * dim + 2]                = 0.5;
2898       }
2899     }
2900     PetscCall(VecRestoreArray(coordinates, &coords));
2901     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2902     PetscCall(VecDestroy(&coordinates));
2903   }
2904   /* Create periodicity */
2905   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
2906     PetscReal L[3]       = {-1., -1., 0.};
2907     PetscReal maxCell[3] = {-1., -1., 0.};
2908     PetscReal lower[3]   = {0.0, 0.0, 0.0};
2909     PetscReal upper[3]   = {1.0, 1.0, 1.5};
2910     PetscInt  numZCells  = 3;
2911 
2912     L[2]       = upper[2] - lower[2];
2913     maxCell[2] = 1.1 * (L[2] / numZCells);
2914     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
2915   }
2916   {
2917     DM          cdm;
2918     PetscDS     cds;
2919     PetscScalar c[2] = {1.0, 1.0};
2920 
2921     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_FALSE, PETSC_TRUE));
2922     PetscCall(DMGetCoordinateDM(dm, &cdm));
2923     PetscCall(DMGetDS(cdm, &cds));
2924     PetscCall(PetscDSSetConstants(cds, 2, c));
2925   }
2926   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2927 
2928   /* Wait for coordinate creation before doing in-place modification */
2929   PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2930 
2931   char        oldprefix[PETSC_MAX_PATH_LEN];
2932   const char *prefix;
2933 
2934   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2935   PetscCall(PetscStrncpy(oldprefix, prefix, PETSC_MAX_PATH_LEN));
2936   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, "petsc_cyl_ref_"));
2937   for (PetscInt r = 0; r < PetscMax(0, Nr); ++r) {
2938     DM rdm;
2939 
2940     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
2941     PetscCall(DMPlexReplace_Internal(dm, &rdm));
2942   }
2943   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldprefix));
2944   PetscCall(DMPlexRemapGeometry(dm, 0.0, snapToCylinder));
2945 
2946   DMLabel         bdlabel, edgelabel;
2947   IS              faceIS;
2948   const PetscInt *faces;
2949   PetscInt        Nf;
2950 
2951   PetscCall(DMCreateLabel(dm, "marker"));
2952   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
2953   PetscCall(DMCreateLabel(dm, "generatrix"));
2954   PetscCall(DMGetLabel(dm, "generatrix", &edgelabel));
2955   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
2956   // Remove faces on top and bottom
2957   PetscCall(DMLabelGetStratumIS(bdlabel, 1, &faceIS));
2958   if (faceIS) {
2959     PetscCall(ISGetLocalSize(faceIS, &Nf));
2960     PetscCall(ISGetIndices(faceIS, &faces));
2961     for (PetscInt f = 0; f < Nf; ++f) {
2962       PetscReal vol, normal[3];
2963 
2964       PetscCall(DMPlexComputeCellGeometryFVM(dm, faces[f], &vol, NULL, normal));
2965       if (PetscAbsReal(normal[2]) < PETSC_SMALL) PetscCall(DMLabelSetValue(edgelabel, faces[f], 1));
2966     }
2967     PetscCall(ISRestoreIndices(faceIS, &faces));
2968     PetscCall(ISDestroy(&faceIS));
2969   }
2970   PetscCall(DMPlexLabelComplete(dm, bdlabel));
2971   PetscCall(DMPlexLabelComplete(dm, edgelabel));
2972   PetscFunctionReturn(PETSC_SUCCESS);
2973 }
2974 
2975 /*@
2976   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.
2977 
2978   Collective
2979 
2980   Input Parameters:
2981 + comm      - The communicator for the `DM` object
2982 . periodicZ - The boundary type for the Z direction
2983 - Nr        - The number of refinements to carry out
2984 
2985   Output Parameter:
2986 . dm - The `DM` object
2987 
2988   Level: beginner
2989 
2990   Note:
2991   Here is the output numbering looking from the bottom of the cylinder\:
2992 .vb
2993        17-----14
2994         |     |
2995         |  2  |
2996         |     |
2997  17-----8-----7-----14
2998   |     |     |     |
2999   |  3  |  0  |  1  |
3000   |     |     |     |
3001  19-----5-----6-----13
3002         |     |
3003         |  4  |
3004         |     |
3005        19-----13
3006 
3007  and up through the top
3008 
3009        18-----16
3010         |     |
3011         |  2  |
3012         |     |
3013  18----10----11-----16
3014   |     |     |     |
3015   |  3  |  0  |  1  |
3016   |     |     |     |
3017  20-----9----12-----15
3018         |     |
3019         |  4  |
3020         |     |
3021        20-----15
3022 .ve
3023 
3024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3025 @*/
DMPlexCreateHexCylinderMesh(MPI_Comm comm,DMBoundaryType periodicZ,PetscInt Nr,DM * dm)3026 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, PetscInt Nr, DM *dm)
3027 {
3028   PetscFunctionBegin;
3029   PetscAssertPointer(dm, 4);
3030   PetscCall(DMCreate(comm, dm));
3031   PetscCall(DMSetType(*dm, DMPLEX));
3032   PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ, Nr));
3033   PetscFunctionReturn(PETSC_SUCCESS);
3034 }
3035 
DMPlexCreateWedgeCylinderMesh_Internal(DM dm,PetscInt n,PetscBool interpolate)3036 static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate)
3037 {
3038   const PetscInt dim = 3;
3039   PetscInt       numCells, numVertices, v;
3040   PetscMPIInt    rank;
3041 
3042   PetscFunctionBegin;
3043   PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n);
3044   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
3045   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3046   PetscCall(DMSetDimension(dm, dim));
3047   /* Must create the celltype label here so that we do not automatically try to compute the types */
3048   PetscCall(DMCreateLabel(dm, "celltype"));
3049   /* Create topology */
3050   {
3051     PetscInt cone[6], c;
3052 
3053     numCells    = rank == 0 ? n : 0;
3054     numVertices = rank == 0 ? 2 * (n + 1) : 0;
3055     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
3056     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
3057     PetscCall(DMSetUp(dm));
3058     for (c = 0; c < numCells; c++) {
3059       cone[0] = c + n * 1;
3060       cone[1] = (c + 1) % n + n * 1;
3061       cone[2] = 0 + 3 * n;
3062       cone[3] = c + n * 2;
3063       cone[4] = (c + 1) % n + n * 2;
3064       cone[5] = 1 + 3 * n;
3065       PetscCall(DMPlexSetCone(dm, c, cone));
3066       PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR));
3067     }
3068     PetscCall(DMPlexSymmetrize(dm));
3069     PetscCall(DMPlexStratify(dm));
3070   }
3071   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT));
3072   /* Create cylinder geometry */
3073   {
3074     Vec          coordinates;
3075     PetscSection coordSection;
3076     PetscScalar *coords;
3077     PetscInt     coordSize, c;
3078 
3079     /* Build coordinates */
3080     PetscCall(DMGetCoordinateSection(dm, &coordSection));
3081     PetscCall(PetscSectionSetNumFields(coordSection, 1));
3082     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
3083     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
3084     for (v = numCells; v < numCells + numVertices; ++v) {
3085       PetscCall(PetscSectionSetDof(coordSection, v, dim));
3086       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
3087     }
3088     PetscCall(PetscSectionSetUp(coordSection));
3089     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
3090     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
3091     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
3092     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
3093     PetscCall(VecSetBlockSize(coordinates, dim));
3094     PetscCall(VecSetType(coordinates, VECSTANDARD));
3095     PetscCall(VecGetArray(coordinates, &coords));
3096     for (c = 0; c < numCells; c++) {
3097       coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
3098       coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
3099       coords[(c + 0 * n) * dim + 2] = 1.0;
3100       coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
3101       coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
3102       coords[(c + 1 * n) * dim + 2] = 0.0;
3103     }
3104     if (rank == 0) {
3105       coords[(2 * n + 0) * dim + 0] = 0.0;
3106       coords[(2 * n + 0) * dim + 1] = 0.0;
3107       coords[(2 * n + 0) * dim + 2] = 1.0;
3108       coords[(2 * n + 1) * dim + 0] = 0.0;
3109       coords[(2 * n + 1) * dim + 1] = 0.0;
3110       coords[(2 * n + 1) * dim + 2] = 0.0;
3111     }
3112     PetscCall(VecRestoreArray(coordinates, &coords));
3113     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
3114     PetscCall(VecDestroy(&coordinates));
3115   }
3116   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
3117   /* Interpolate */
3118   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
3119   PetscFunctionReturn(PETSC_SUCCESS);
3120 }
3121 
3122 /*@
3123   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.
3124 
3125   Collective
3126 
3127   Input Parameters:
3128 + comm        - The communicator for the `DM` object
3129 . n           - The number of wedges around the origin
3130 - interpolate - Create edges and faces
3131 
3132   Output Parameter:
3133 . dm - The `DM` object
3134 
3135   Level: beginner
3136 
3137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3138 @*/
DMPlexCreateWedgeCylinderMesh(MPI_Comm comm,PetscInt n,PetscBool interpolate,DM * dm)3139 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
3140 {
3141   PetscFunctionBegin;
3142   PetscAssertPointer(dm, 4);
3143   PetscCall(DMCreate(comm, dm));
3144   PetscCall(DMSetType(*dm, DMPLEX));
3145   PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate));
3146   PetscFunctionReturn(PETSC_SUCCESS);
3147 }
3148 
DiffNormReal(PetscInt dim,const PetscReal x[],const PetscReal y[])3149 static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
3150 {
3151   PetscReal prod = 0.0;
3152   PetscInt  i;
3153   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
3154   return PetscSqrtReal(prod);
3155 }
3156 
DotReal(PetscInt dim,const PetscReal x[],const PetscReal y[])3157 static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
3158 {
3159   PetscReal prod = 0.0;
3160   PetscInt  i;
3161   for (i = 0; i < dim; ++i) prod += x[i] * y[i];
3162   return prod;
3163 }
3164 
3165 /* The first constant is the sphere radius */
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[])3166 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[])
3167 {
3168   PetscReal r     = PetscRealPart(constants[0]);
3169   PetscReal norm2 = 0.0, fac;
3170   PetscInt  n     = uOff[1] - uOff[0], d;
3171 
3172   for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d]));
3173   fac = r / PetscSqrtReal(norm2);
3174   for (d = 0; d < n; ++d) f0[d] = u[d] * fac;
3175 }
3176 
DMPlexCreateSphereMesh_Internal(DM dm,PetscInt dim,PetscBool simplex,PetscReal R)3177 static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R)
3178 {
3179   const PetscInt embedDim = dim + 1;
3180   PetscSection   coordSection;
3181   Vec            coordinates;
3182   PetscScalar   *coords;
3183   PetscReal     *coordsIn;
3184   PetscInt       numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e;
3185   PetscMPIInt    rank;
3186 
3187   PetscFunctionBegin;
3188   PetscValidLogicalCollectiveBool(dm, simplex, 3);
3189   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
3190   PetscCall(DMSetDimension(dm, dim));
3191   PetscCall(DMSetCoordinateDim(dm, dim + 1));
3192   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3193   switch (dim) {
3194   case 1:
3195     numCells = 16;
3196     numVerts = numCells;
3197 
3198     // Build Topology
3199     PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
3200     for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
3201     PetscCall(DMSetUp(dm));
3202     for (PetscInt c = 0; c < numCells; ++c) {
3203       PetscInt cone[2];
3204 
3205       cone[0] = c + numCells;
3206       cone[1] = (c + 1) % numVerts + numCells;
3207       PetscCall(DMPlexSetCone(dm, c, cone));
3208     }
3209     PetscCall(DMPlexSymmetrize(dm));
3210     PetscCall(DMPlexStratify(dm));
3211     PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn));
3212     for (PetscInt v = 0; v < numVerts; ++v) {
3213       const PetscReal rad = 2. * PETSC_PI * v / numVerts;
3214 
3215       coordsIn[v * embedDim + 0] = PetscCosReal(rad);
3216       coordsIn[v * embedDim + 1] = PetscSinReal(rad);
3217     }
3218     break;
3219   case 2:
3220     if (simplex) {
3221       const PetscReal radius    = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI);
3222       const PetscReal edgeLen   = 2.0 / (1.0 + PETSC_PHI) * (R / radius);
3223       const PetscInt  degree    = 5;
3224       PetscReal       vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)};
3225       PetscInt        s[3]      = {1, 1, 1};
3226       PetscInt        cone[3];
3227       PetscInt       *graph;
3228 
3229       vertex[0] *= R / radius;
3230       vertex[1] *= R / radius;
3231       vertex[2] *= R / radius;
3232       numCells    = rank == 0 ? 20 : 0;
3233       numVerts    = rank == 0 ? 12 : 0;
3234       firstVertex = numCells;
3235       /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of
3236 
3237            (0, \pm 1/\phi+1, \pm \phi/\phi+1)
3238 
3239          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
3240          length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393.
3241       */
3242       /* Construct vertices */
3243       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
3244       if (rank == 0) {
3245         for (PetscInt p = 0, i = 0; p < embedDim; ++p) {
3246           for (s[1] = -1; s[1] < 2; s[1] += 2) {
3247             for (s[2] = -1; s[2] < 2; s[2] += 2) {
3248               for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim];
3249               ++i;
3250             }
3251           }
3252         }
3253       }
3254       /* Construct graph */
3255       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
3256       for (PetscInt i = 0; i < numVerts; ++i) {
3257         PetscInt k = 0;
3258         for (PetscInt j = 0; j < numVerts; ++j) {
3259           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
3260             graph[i * numVerts + j] = 1;
3261             ++k;
3262           }
3263         }
3264         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
3265       }
3266       /* Build Topology */
3267       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
3268       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
3269       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
3270       /* Cells */
3271       for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
3272         for (PetscInt j = 0; j < i; ++j) {
3273           for (PetscInt k = 0; k < j; ++k) {
3274             if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) {
3275               cone[0] = firstVertex + i;
3276               cone[1] = firstVertex + j;
3277               cone[2] = firstVertex + k;
3278               /* Check orientation */
3279               {
3280                 const PetscInt epsilon[3][3][3] = {
3281                   {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
3282                   {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
3283                   {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
3284                 };
3285                 PetscReal normal[3];
3286                 PetscInt  e, f;
3287 
3288                 for (d = 0; d < embedDim; ++d) {
3289                   normal[d] = 0.0;
3290                   for (e = 0; e < embedDim; ++e) {
3291                     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]);
3292                   }
3293                 }
3294                 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
3295                   PetscInt tmp = cone[1];
3296                   cone[1]      = cone[2];
3297                   cone[2]      = tmp;
3298                 }
3299               }
3300               PetscCall(DMPlexSetCone(dm, c++, cone));
3301             }
3302           }
3303         }
3304       }
3305       PetscCall(DMPlexSymmetrize(dm));
3306       PetscCall(DMPlexStratify(dm));
3307       PetscCall(PetscFree(graph));
3308     } else {
3309       /*
3310         12-21--13
3311          |     |
3312         25  4  24
3313          |     |
3314   12-25--9-16--8-24--13
3315    |     |     |     |
3316   23  5 17  0 15  3  22
3317    |     |     |     |
3318   10-20--6-14--7-19--11
3319          |     |
3320         20  1  19
3321          |     |
3322         10-18--11
3323          |     |
3324         23  2  22
3325          |     |
3326         12-21--13
3327        */
3328       PetscInt cone[4], ornt[4];
3329 
3330       numCells    = rank == 0 ? 6 : 0;
3331       numEdges    = rank == 0 ? 12 : 0;
3332       numVerts    = rank == 0 ? 8 : 0;
3333       firstVertex = numCells;
3334       firstEdge   = numCells + numVerts;
3335       /* Build Topology */
3336       PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts));
3337       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4));
3338       for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
3339       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
3340       if (rank == 0) {
3341         /* Cell 0 */
3342         cone[0] = 14;
3343         cone[1] = 15;
3344         cone[2] = 16;
3345         cone[3] = 17;
3346         PetscCall(DMPlexSetCone(dm, 0, cone));
3347         ornt[0] = 0;
3348         ornt[1] = 0;
3349         ornt[2] = 0;
3350         ornt[3] = 0;
3351         PetscCall(DMPlexSetConeOrientation(dm, 0, ornt));
3352         /* Cell 1 */
3353         cone[0] = 18;
3354         cone[1] = 19;
3355         cone[2] = 14;
3356         cone[3] = 20;
3357         PetscCall(DMPlexSetCone(dm, 1, cone));
3358         ornt[0] = 0;
3359         ornt[1] = 0;
3360         ornt[2] = -1;
3361         ornt[3] = 0;
3362         PetscCall(DMPlexSetConeOrientation(dm, 1, ornt));
3363         /* Cell 2 */
3364         cone[0] = 21;
3365         cone[1] = 22;
3366         cone[2] = 18;
3367         cone[3] = 23;
3368         PetscCall(DMPlexSetCone(dm, 2, cone));
3369         ornt[0] = 0;
3370         ornt[1] = 0;
3371         ornt[2] = -1;
3372         ornt[3] = 0;
3373         PetscCall(DMPlexSetConeOrientation(dm, 2, ornt));
3374         /* Cell 3 */
3375         cone[0] = 19;
3376         cone[1] = 22;
3377         cone[2] = 24;
3378         cone[3] = 15;
3379         PetscCall(DMPlexSetCone(dm, 3, cone));
3380         ornt[0] = -1;
3381         ornt[1] = -1;
3382         ornt[2] = 0;
3383         ornt[3] = -1;
3384         PetscCall(DMPlexSetConeOrientation(dm, 3, ornt));
3385         /* Cell 4 */
3386         cone[0] = 16;
3387         cone[1] = 24;
3388         cone[2] = 21;
3389         cone[3] = 25;
3390         PetscCall(DMPlexSetCone(dm, 4, cone));
3391         ornt[0] = -1;
3392         ornt[1] = -1;
3393         ornt[2] = -1;
3394         ornt[3] = 0;
3395         PetscCall(DMPlexSetConeOrientation(dm, 4, ornt));
3396         /* Cell 5 */
3397         cone[0] = 20;
3398         cone[1] = 17;
3399         cone[2] = 25;
3400         cone[3] = 23;
3401         PetscCall(DMPlexSetCone(dm, 5, cone));
3402         ornt[0] = -1;
3403         ornt[1] = -1;
3404         ornt[2] = -1;
3405         ornt[3] = -1;
3406         PetscCall(DMPlexSetConeOrientation(dm, 5, ornt));
3407         /* Edges */
3408         cone[0] = 6;
3409         cone[1] = 7;
3410         PetscCall(DMPlexSetCone(dm, 14, cone));
3411         cone[0] = 7;
3412         cone[1] = 8;
3413         PetscCall(DMPlexSetCone(dm, 15, cone));
3414         cone[0] = 8;
3415         cone[1] = 9;
3416         PetscCall(DMPlexSetCone(dm, 16, cone));
3417         cone[0] = 9;
3418         cone[1] = 6;
3419         PetscCall(DMPlexSetCone(dm, 17, cone));
3420         cone[0] = 10;
3421         cone[1] = 11;
3422         PetscCall(DMPlexSetCone(dm, 18, cone));
3423         cone[0] = 11;
3424         cone[1] = 7;
3425         PetscCall(DMPlexSetCone(dm, 19, cone));
3426         cone[0] = 6;
3427         cone[1] = 10;
3428         PetscCall(DMPlexSetCone(dm, 20, cone));
3429         cone[0] = 12;
3430         cone[1] = 13;
3431         PetscCall(DMPlexSetCone(dm, 21, cone));
3432         cone[0] = 13;
3433         cone[1] = 11;
3434         PetscCall(DMPlexSetCone(dm, 22, cone));
3435         cone[0] = 10;
3436         cone[1] = 12;
3437         PetscCall(DMPlexSetCone(dm, 23, cone));
3438         cone[0] = 13;
3439         cone[1] = 8;
3440         PetscCall(DMPlexSetCone(dm, 24, cone));
3441         cone[0] = 12;
3442         cone[1] = 9;
3443         PetscCall(DMPlexSetCone(dm, 25, cone));
3444       }
3445       PetscCall(DMPlexSymmetrize(dm));
3446       PetscCall(DMPlexStratify(dm));
3447       /* Build coordinates */
3448       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
3449       if (rank == 0) {
3450         coordsIn[0 * embedDim + 0] = -R;
3451         coordsIn[0 * embedDim + 1] = R;
3452         coordsIn[0 * embedDim + 2] = -R;
3453         coordsIn[1 * embedDim + 0] = R;
3454         coordsIn[1 * embedDim + 1] = R;
3455         coordsIn[1 * embedDim + 2] = -R;
3456         coordsIn[2 * embedDim + 0] = R;
3457         coordsIn[2 * embedDim + 1] = -R;
3458         coordsIn[2 * embedDim + 2] = -R;
3459         coordsIn[3 * embedDim + 0] = -R;
3460         coordsIn[3 * embedDim + 1] = -R;
3461         coordsIn[3 * embedDim + 2] = -R;
3462         coordsIn[4 * embedDim + 0] = -R;
3463         coordsIn[4 * embedDim + 1] = R;
3464         coordsIn[4 * embedDim + 2] = R;
3465         coordsIn[5 * embedDim + 0] = R;
3466         coordsIn[5 * embedDim + 1] = R;
3467         coordsIn[5 * embedDim + 2] = R;
3468         coordsIn[6 * embedDim + 0] = -R;
3469         coordsIn[6 * embedDim + 1] = -R;
3470         coordsIn[6 * embedDim + 2] = R;
3471         coordsIn[7 * embedDim + 0] = R;
3472         coordsIn[7 * embedDim + 1] = -R;
3473         coordsIn[7 * embedDim + 2] = R;
3474       }
3475     }
3476     break;
3477   case 3:
3478     if (simplex) {
3479       const PetscReal edgeLen         = 1.0 / PETSC_PHI;
3480       PetscReal       vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
3481       PetscReal       vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
3482       PetscReal       vertexC[4]      = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0};
3483       const PetscInt  degree          = 12;
3484       PetscInt        s[4]            = {1, 1, 1};
3485       PetscInt        evenPerm[12][4] = {
3486         {0, 1, 2, 3},
3487         {0, 2, 3, 1},
3488         {0, 3, 1, 2},
3489         {1, 0, 3, 2},
3490         {1, 2, 0, 3},
3491         {1, 3, 2, 0},
3492         {2, 0, 1, 3},
3493         {2, 1, 3, 0},
3494         {2, 3, 0, 1},
3495         {3, 0, 2, 1},
3496         {3, 1, 0, 2},
3497         {3, 2, 1, 0}
3498       };
3499       PetscInt  cone[4];
3500       PetscInt *graph, p, i, j, k, l;
3501 
3502       vertexA[0] *= R;
3503       vertexA[1] *= R;
3504       vertexA[2] *= R;
3505       vertexA[3] *= R;
3506       vertexB[0] *= R;
3507       vertexB[1] *= R;
3508       vertexB[2] *= R;
3509       vertexB[3] *= R;
3510       vertexC[0] *= R;
3511       vertexC[1] *= R;
3512       vertexC[2] *= R;
3513       vertexC[3] *= R;
3514       numCells    = rank == 0 ? 600 : 0;
3515       numVerts    = rank == 0 ? 120 : 0;
3516       firstVertex = numCells;
3517       /* Use the 600-cell, which for a unit sphere has coordinates which are
3518 
3519            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
3520                (\pm 1,    0,       0,      0)  all cyclic permutations   8
3521            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96
3522 
3523          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
3524          length is then given by 1/\phi = 0.61803.
3525 
3526          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
3527          http://mathworld.wolfram.com/600-Cell.html
3528       */
3529       /* Construct vertices */
3530       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
3531       i = 0;
3532       if (rank == 0) {
3533         for (s[0] = -1; s[0] < 2; s[0] += 2) {
3534           for (s[1] = -1; s[1] < 2; s[1] += 2) {
3535             for (s[2] = -1; s[2] < 2; s[2] += 2) {
3536               for (s[3] = -1; s[3] < 2; s[3] += 2) {
3537                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d];
3538                 ++i;
3539               }
3540             }
3541           }
3542         }
3543         for (p = 0; p < embedDim; ++p) {
3544           s[1] = s[2] = s[3] = 1;
3545           for (s[0] = -1; s[0] < 2; s[0] += 2) {
3546             for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim];
3547             ++i;
3548           }
3549         }
3550         for (p = 0; p < 12; ++p) {
3551           s[3] = 1;
3552           for (s[0] = -1; s[0] < 2; s[0] += 2) {
3553             for (s[1] = -1; s[1] < 2; s[1] += 2) {
3554               for (s[2] = -1; s[2] < 2; s[2] += 2) {
3555                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]];
3556                 ++i;
3557               }
3558             }
3559           }
3560         }
3561       }
3562       PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts);
3563       /* Construct graph */
3564       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
3565       for (i = 0; i < numVerts; ++i) {
3566         for (j = 0, k = 0; j < numVerts; ++j) {
3567           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
3568             graph[i * numVerts + j] = 1;
3569             ++k;
3570           }
3571         }
3572         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
3573       }
3574       /* Build Topology */
3575       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
3576       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
3577       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
3578       /* Cells */
3579       if (rank == 0) {
3580         for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
3581           for (j = 0; j < i; ++j) {
3582             for (k = 0; k < j; ++k) {
3583               for (l = 0; l < k; ++l) {
3584                 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]) {
3585                   cone[0] = firstVertex + i;
3586                   cone[1] = firstVertex + j;
3587                   cone[2] = firstVertex + k;
3588                   cone[3] = firstVertex + l;
3589                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
3590                   {
3591                     const PetscInt epsilon[4][4][4][4] = {
3592                       {{{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}}},
3593 
3594                       {{{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}}},
3595 
3596                       {{{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}}},
3597 
3598                       {{{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}} }
3599                     };
3600                     PetscReal normal[4];
3601                     PetscInt  e, f, g;
3602 
3603                     for (d = 0; d < embedDim; ++d) {
3604                       normal[d] = 0.0;
3605                       for (e = 0; e < embedDim; ++e) {
3606                         for (f = 0; f < embedDim; ++f) {
3607                           for (g = 0; g < embedDim; ++g) {
3608                             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]);
3609                           }
3610                         }
3611                       }
3612                     }
3613                     if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
3614                       PetscInt tmp = cone[1];
3615                       cone[1]      = cone[2];
3616                       cone[2]      = tmp;
3617                     }
3618                   }
3619                   PetscCall(DMPlexSetCone(dm, c++, cone));
3620                 }
3621               }
3622             }
3623           }
3624         }
3625       }
3626       PetscCall(DMPlexSymmetrize(dm));
3627       PetscCall(DMPlexStratify(dm));
3628       PetscCall(PetscFree(graph));
3629     }
3630     break;
3631   default:
3632     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim);
3633   }
3634   /* Create coordinates */
3635   PetscCall(DMGetCoordinateSection(dm, &coordSection));
3636   PetscCall(PetscSectionSetNumFields(coordSection, 1));
3637   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim));
3638   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts));
3639   for (v = firstVertex; v < firstVertex + numVerts; ++v) {
3640     PetscCall(PetscSectionSetDof(coordSection, v, embedDim));
3641     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim));
3642   }
3643   PetscCall(PetscSectionSetUp(coordSection));
3644   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
3645   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
3646   PetscCall(VecSetBlockSize(coordinates, embedDim));
3647   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
3648   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
3649   PetscCall(VecSetType(coordinates, VECSTANDARD));
3650   PetscCall(VecGetArray(coordinates, &coords));
3651   for (v = 0; v < numVerts; ++v)
3652     for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d];
3653   PetscCall(VecRestoreArray(coordinates, &coords));
3654   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
3655   PetscCall(VecDestroy(&coordinates));
3656   PetscCall(PetscFree(coordsIn));
3657   {
3658     DM          cdm;
3659     PetscDS     cds;
3660     PetscScalar c = R;
3661 
3662     PetscCall(DMPlexSetCoordinateMap(dm, snapToSphere));
3663     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_FALSE, PETSC_TRUE));
3664     PetscCall(DMGetCoordinateDM(dm, &cdm));
3665     PetscCall(DMGetDS(cdm, &cds));
3666     PetscCall(PetscDSSetConstants(cds, 1, &c));
3667   }
3668   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
3669   /* Wait for coordinate creation before doing in-place modification */
3670   if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
3671   PetscFunctionReturn(PETSC_SUCCESS);
3672 }
3673 
3674 typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]);
3675 
3676 /*
3677  The Schwarz P implicit surface is
3678 
3679      f(x) = cos(x0) + cos(x1) + cos(x2) = 0
3680 */
TPSEvaluate_SchwarzP(const PetscReal y[3],PetscReal * f,PetscReal grad[],PetscReal (* hess)[3])3681 static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
3682 {
3683   PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)};
3684   PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)};
3685   f[0]           = c[0] + c[1] + c[2];
3686   for (PetscInt i = 0; i < 3; i++) {
3687     grad[i] = PETSC_PI * g[i];
3688     for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.;
3689   }
3690 }
3691 
3692 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
TPSExtrudeNormalFunc_SchwarzP(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt r,PetscScalar u[],PetscCtx ctx)3693 static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], PetscCtx ctx)
3694 {
3695   for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI);
3696   return PETSC_SUCCESS;
3697 }
3698 
3699 /*
3700  The Gyroid implicit surface is
3701 
3702  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)
3703 
3704 */
TPSEvaluate_Gyroid(const PetscReal y[3],PetscReal * f,PetscReal grad[],PetscReal (* hess)[3])3705 static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
3706 {
3707   PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))};
3708   PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))};
3709   f[0]           = s[0] * c[1] + s[1] * c[2] + s[2] * c[0];
3710   grad[0]        = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
3711   grad[1]        = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
3712   grad[2]        = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
3713   hess[0][0]     = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]);
3714   hess[0][1]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
3715   hess[0][2]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
3716   hess[1][0]     = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]);
3717   hess[1][1]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
3718   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
3719   hess[2][0]     = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]);
3720   hess[2][1]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
3721   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
3722 }
3723 
3724 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
TPSExtrudeNormalFunc_Gyroid(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt r,PetscScalar u[],PetscCtx ctx)3725 static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], PetscCtx ctx)
3726 {
3727   PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))};
3728   PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))};
3729   u[0]           = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
3730   u[1]           = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
3731   u[2]           = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
3732   return PETSC_SUCCESS;
3733 }
3734 
3735 /*
3736    We wish to solve
3737 
3738          min_y || y - x ||^2  subject to f(y) = 0
3739 
3740    Let g(y) = grad(f).  The minimization problem is equivalent to asking to satisfy
3741    f(y) = 0 and (y-x) is parallel to g(y).  We do this by using Householder QR to obtain a basis for the
3742    tangent space and ask for both components in the tangent space to be zero.
3743 
3744    Take g to be a column vector and compute the "full QR" factorization Q R = g,
3745    where Q = I - 2 n n^T is a symmetric orthogonal matrix.
3746    The first column of Q is parallel to g so the remaining two columns span the null space.
3747    Let Qn = Q[:,1:] be those remaining columns.  Then Qn Qn^T is an orthogonal projector into the tangent space.
3748    Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries.
3749    In total, we have a system of 3 equations in 3 unknowns:
3750 
3751      f(y) = 0                       1 equation
3752      Qn^T (y - x) = 0               2 equations
3753 
3754    Here, we compute the residual and Jacobian of this system.
3755 */
TPSNearestPointResJac(TPSEvaluateFunc feval,const PetscScalar x[],const PetscScalar y[],PetscScalar res[],PetscScalar J[])3756 static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[])
3757 {
3758   PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])};
3759   PetscReal d[3]     = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])};
3760   PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign;
3761   PetscReal n_y[3][3] = {
3762     {0, 0, 0},
3763     {0, 0, 0},
3764     {0, 0, 0}
3765   };
3766 
3767   feval(yreal, &f, grad, n_y);
3768 
3769   for (PetscInt i = 0; i < 3; i++) n[i] = grad[i];
3770   norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
3771   for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i];
3772 
3773   // Define the Householder reflector
3774   sign = n[0] >= 0 ? 1. : -1.;
3775   n[0] += norm * sign;
3776   for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign;
3777 
3778   norm      = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
3779   norm_y[0] = 1. / norm * (n[0] * n_y[0][0]);
3780   norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]);
3781   norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]);
3782 
3783   for (PetscInt i = 0; i < 3; i++) {
3784     n[i] /= norm;
3785     for (PetscInt j = 0; j < 3; j++) {
3786       // note that n[i] is n_old[i]/norm when executing the code below
3787       n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j];
3788     }
3789   }
3790 
3791   nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2];
3792   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];
3793 
3794   res[0] = f;
3795   res[1] = d[1] - 2 * n[1] * nd;
3796   res[2] = d[2] - 2 * n[2] * nd;
3797   // J[j][i] is J_{ij} (column major)
3798   for (PetscInt j = 0; j < 3; j++) {
3799     J[0 + j * 3] = grad[j];
3800     J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]);
3801     J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]);
3802   }
3803 }
3804 
3805 /*
3806    Project x to the nearest point on the implicit surface using Newton's method.
3807 */
TPSNearestPoint(TPSEvaluateFunc feval,PetscScalar x[])3808 static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[])
3809 {
3810   PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess
3811 
3812   PetscFunctionBegin;
3813   for (PetscInt iter = 0; iter < 10; iter++) {
3814     PetscScalar res[3], J[9];
3815     PetscReal   resnorm;
3816     TPSNearestPointResJac(feval, x, y, res, J);
3817     resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2])));
3818     if (0) { // Turn on this monitor if you need to confirm quadratic convergence
3819       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])));
3820     }
3821     if (resnorm < PETSC_SMALL) break;
3822 
3823     // Take the Newton step
3824     PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL));
3825     PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res);
3826   }
3827   for (PetscInt i = 0; i < 3; i++) x[i] = y[i];
3828   PetscFunctionReturn(PETSC_SUCCESS);
3829 }
3830 
3831 const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL};
3832 
DMPlexCreateTPSMesh_Internal(DM dm,DMPlexTPSType tpstype,const PetscInt extent[],const DMBoundaryType periodic[],PetscBool tps_distribute,PetscInt refinements,PetscInt layers,PetscReal thickness)3833 static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness)
3834 {
3835   PetscMPIInt rank;
3836   PetscInt    topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0;
3837   PetscInt (*edges)[2] = NULL, *edgeSets = NULL;
3838   PetscInt           *cells_flat = NULL;
3839   PetscReal          *vtxCoords  = NULL;
3840   TPSEvaluateFunc     evalFunc   = NULL;
3841   PetscSimplePointFn *normalFunc = NULL;
3842   DMLabel             label;
3843 
3844   PetscFunctionBegin;
3845   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
3846   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3847   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);
3848   switch (tpstype) {
3849   case DMPLEX_TPS_SCHWARZ_P:
3850     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");
3851     if (rank == 0) {
3852       PetscInt (*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn]
3853       PetscInt  Njunctions = 0, Ncuts = 0, Npipes[3], vcount;
3854       PetscReal L = 1;
3855 
3856       Npipes[0]   = (extent[0] + 1) * extent[1] * extent[2];
3857       Npipes[1]   = extent[0] * (extent[1] + 1) * extent[2];
3858       Npipes[2]   = extent[0] * extent[1] * (extent[2] + 1);
3859       Njunctions  = extent[0] * extent[1] * extent[2];
3860       Ncuts       = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]);
3861       numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions;
3862       PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords));
3863       PetscCall(PetscMalloc1(Njunctions, &cells));
3864       PetscCall(PetscMalloc1(Ncuts * 4, &edges));
3865       PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets));
3866       // x-normal pipes
3867       vcount = 0;
3868       for (PetscInt i = 0; i < extent[0] + 1; i++) {
3869         for (PetscInt j = 0; j < extent[1]; j++) {
3870           for (PetscInt k = 0; k < extent[2]; k++) {
3871             for (PetscInt l = 0; l < 4; l++) {
3872               vtxCoords[vcount++] = (2 * i - 1) * L;
3873               vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3874               vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3875             }
3876           }
3877         }
3878       }
3879       // y-normal pipes
3880       for (PetscInt i = 0; i < extent[0]; i++) {
3881         for (PetscInt j = 0; j < extent[1] + 1; j++) {
3882           for (PetscInt k = 0; k < extent[2]; k++) {
3883             for (PetscInt l = 0; l < 4; l++) {
3884               vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3885               vtxCoords[vcount++] = (2 * j - 1) * L;
3886               vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3887             }
3888           }
3889         }
3890       }
3891       // z-normal pipes
3892       for (PetscInt i = 0; i < extent[0]; i++) {
3893         for (PetscInt j = 0; j < extent[1]; j++) {
3894           for (PetscInt k = 0; k < extent[2] + 1; k++) {
3895             for (PetscInt l = 0; l < 4; l++) {
3896               vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3897               vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3898               vtxCoords[vcount++] = (2 * k - 1) * L;
3899             }
3900           }
3901         }
3902       }
3903       // junctions
3904       for (PetscInt i = 0; i < extent[0]; i++) {
3905         for (PetscInt j = 0; j < extent[1]; j++) {
3906           for (PetscInt k = 0; k < extent[2]; k++) {
3907             const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8;
3908             PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count");
3909             for (PetscInt ii = 0; ii < 2; ii++) {
3910               for (PetscInt jj = 0; jj < 2; jj++) {
3911                 for (PetscInt kk = 0; kk < 2; kk++) {
3912                   double Ls           = (1 - sqrt(2) / 4) * L;
3913                   vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls;
3914                   vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls;
3915                   vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls;
3916                 }
3917               }
3918             }
3919             const PetscInt jfaces[3][2][4] = {
3920               {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned
3921               {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned
3922               {{6, 2, 0, 4}, {7, 3, 1, 5}}  // z-aligned
3923             };
3924             const PetscInt pipe_lo[3] = {// vertex numbers of pipes
3925                                          ((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};
3926             const PetscInt pipe_hi[3] = {// vertex numbers of pipes
3927                                          (((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};
3928             for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z
3929               const PetscInt ijk[3] = {i, j, k};
3930               for (PetscInt l = 0; l < 4; l++) { // rotations
3931                 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l;
3932                 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l];
3933                 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4];
3934                 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4;
3935                 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l];
3936                 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l;
3937                 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4;
3938                 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4];
3939                 if (ijk[dir] == 0) {
3940                   edges[numEdges][0] = pipe_lo[dir] + l;
3941                   edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4;
3942                   edgeSets[numEdges] = dir * 2 + 1;
3943                   numEdges++;
3944                 }
3945                 if (ijk[dir] + 1 == extent[dir]) {
3946                   edges[numEdges][0] = pipe_hi[dir] + l;
3947                   edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4;
3948                   edgeSets[numEdges] = dir * 2 + 2;
3949                   numEdges++;
3950                 }
3951               }
3952             }
3953           }
3954         }
3955       }
3956       PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts);
3957       numFaces   = 24 * Njunctions;
3958       cells_flat = cells[0][0][0];
3959     }
3960     evalFunc   = TPSEvaluate_SchwarzP;
3961     normalFunc = TPSExtrudeNormalFunc_SchwarzP;
3962     break;
3963   case DMPLEX_TPS_GYROID:
3964     if (rank == 0) {
3965       // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set
3966       //
3967       //     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)
3968       //
3969       // on the cell [0,2]^3.
3970       //
3971       // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2].
3972       // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins
3973       // like a boomerang:
3974       //
3975       //     z = 0          z = 1/4        z = 1/2        z = 3/4     //
3976       //     -----          -------        -------        -------     //
3977       //                                                              //
3978       //     +       +      +       +      +       +      +   \   +   //
3979       //      \                                   /            \      //
3980       //       \            `-_   _-'            /              }     //
3981       //        *-_            `-'            _-'              /      //
3982       //     +     `-+      +       +      +-'     +      +   /   +   //
3983       //                                                              //
3984       //                                                              //
3985       //     z = 1          z = 5/4        z = 3/2        z = 7/4     //
3986       //     -----          -------        -------        -------     //
3987       //                                                              //
3988       //     +-_     +      +       +      +     _-+      +   /   +   //
3989       //        `-_            _-_            _-`            /        //
3990       //           \        _-'   `-_        /              {         //
3991       //            \                       /                \        //
3992       //     +       +      +       +      +       +      +   \   +   //
3993       //
3994       //
3995       // This course mesh approximates each of these slices by two line segments,
3996       // and then connects the segments in consecutive layers with quadrilateral faces.
3997       // All of the end points of the segments are multiples of 1/4 except for the
3998       // point * in the picture for z = 0 above and the similar points in other layers.
3999       // That point is at (gamma, gamma, 0), where gamma is calculated below.
4000       //
4001       // The column  [1,2]x[1,2]x[0,2] looks the same as this column;
4002       // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images.
4003       //
4004       // As for how this method turned into the names given to the vertices:
4005       // that was not systematic, it was just the way it worked out in my handwritten notes.
4006 
4007       PetscInt facesPerBlock = 64;
4008       PetscInt vertsPerBlock = 56;
4009       PetscInt extentPlus[3];
4010       PetscInt numBlocks, numBlocksPlus;
4011       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;
4012       const PetscInt pattern[64][4] = {
4013         /* face to vertex within the coarse discretization of a single gyroid block */
4014         /* layer 0 */
4015         {A,           C,           K,           G          },
4016         {C,           B,           II,          K          },
4017         {D,           A,           H,           L          },
4018         {B + 56 * 1,  D,           L,           J          },
4019         {E,           B + 56 * 1,  J,           N          },
4020         {A + 56 * 2,  E,           N,           H + 56 * 2 },
4021         {F,           A + 56 * 2,  G + 56 * 2,  M          },
4022         {B,           F,           M,           II         },
4023         /* layer 1 */
4024         {G,           K,           Q,           O          },
4025         {K,           II,          P,           Q          },
4026         {L,           H,           O + 56 * 1,  R          },
4027         {J,           L,           R,           P          },
4028         {N,           J,           P,           S          },
4029         {H + 56 * 2,  N,           S,           O + 56 * 3 },
4030         {M,           G + 56 * 2,  O + 56 * 2,  T          },
4031         {II,          M,           T,           P          },
4032         /* layer 2 */
4033         {O,           Q,           Y,           U          },
4034         {Q,           P,           W,           Y          },
4035         {R,           O + 56 * 1,  U + 56 * 1,  Ap         },
4036         {P,           R,           Ap,          W          },
4037         {S,           P,           X,           Bp         },
4038         {O + 56 * 3,  S,           Bp,          V + 56 * 1 },
4039         {T,           O + 56 * 2,  V,           Z          },
4040         {P,           T,           Z,           X          },
4041         /* layer 3 */
4042         {U,           Y,           Ep,          Dp         },
4043         {Y,           W,           Cp,          Ep         },
4044         {Ap,          U + 56 * 1,  Dp + 56 * 1, Gp         },
4045         {W,           Ap,          Gp,          Cp         },
4046         {Bp,          X,           Cp + 56 * 2, Fp         },
4047         {V + 56 * 1,  Bp,          Fp,          Dp + 56 * 1},
4048         {Z,           V,           Dp,          Hp         },
4049         {X,           Z,           Hp,          Cp + 56 * 2},
4050         /* layer 4 */
4051         {Dp,          Ep,          Mp,          Kp         },
4052         {Ep,          Cp,          Ip,          Mp         },
4053         {Gp,          Dp + 56 * 1, Lp,          Np         },
4054         {Cp,          Gp,          Np,          Jp         },
4055         {Fp,          Cp + 56 * 2, Jp + 56 * 2, Pp         },
4056         {Dp + 56 * 1, Fp,          Pp,          Lp         },
4057         {Hp,          Dp,          Kp,          Op         },
4058         {Cp + 56 * 2, Hp,          Op,          Ip + 56 * 2},
4059         /* layer 5 */
4060         {Kp,          Mp,          Sp,          Rp         },
4061         {Mp,          Ip,          Qp,          Sp         },
4062         {Np,          Lp,          Rp,          Tp         },
4063         {Jp,          Np,          Tp,          Qp + 56 * 1},
4064         {Pp,          Jp + 56 * 2, Qp + 56 * 3, Up         },
4065         {Lp,          Pp,          Up,          Rp         },
4066         {Op,          Kp,          Rp,          Vp         },
4067         {Ip + 56 * 2, Op,          Vp,          Qp + 56 * 2},
4068         /* layer 6 */
4069         {Rp,          Sp,          Aq,          Yp         },
4070         {Sp,          Qp,          Wp,          Aq         },
4071         {Tp,          Rp,          Yp,          Cq         },
4072         {Qp + 56 * 1, Tp,          Cq,          Wp + 56 * 1},
4073         {Up,          Qp + 56 * 3, Xp + 56 * 1, Dq         },
4074         {Rp,          Up,          Dq,          Zp         },
4075         {Vp,          Rp,          Zp,          Bq         },
4076         {Qp + 56 * 2, Vp,          Bq,          Xp         },
4077         /* layer 7 (the top is the periodic image of the bottom of layer 0) */
4078         {Yp,          Aq,          C + 56 * 4,  A + 56 * 4 },
4079         {Aq,          Wp,          B + 56 * 4,  C + 56 * 4 },
4080         {Cq,          Yp,          A + 56 * 4,  D + 56 * 4 },
4081         {Wp + 56 * 1, Cq,          D + 56 * 4,  B + 56 * 5 },
4082         {Dq,          Xp + 56 * 1, B + 56 * 5,  E + 56 * 4 },
4083         {Zp,          Dq,          E + 56 * 4,  A + 56 * 6 },
4084         {Bq,          Zp,          A + 56 * 6,  F + 56 * 4 },
4085         {Xp,          Bq,          F + 56 * 4,  B + 56 * 4 }
4086       };
4087       const PetscReal gamma                = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI;
4088       const PetscReal patternCoords[56][3] = {
4089         {1.,        0.,        0.  }, /* A  */
4090         {0.,        1.,        0.  }, /* B  */
4091         {gamma,     gamma,     0.  }, /* C  */
4092         {1 + gamma, 1 - gamma, 0.  }, /* D  */
4093         {2 - gamma, 2 - gamma, 0.  }, /* E  */
4094         {1 - gamma, 1 + gamma, 0.  }, /* F  */
4095 
4096         {.5,        0,         .25 }, /* G  */
4097         {1.5,       0.,        .25 }, /* H  */
4098         {.5,        1.,        .25 }, /* II */
4099         {1.5,       1.,        .25 }, /* J  */
4100         {.25,       .5,        .25 }, /* K  */
4101         {1.25,      .5,        .25 }, /* L  */
4102         {.75,       1.5,       .25 }, /* M  */
4103         {1.75,      1.5,       .25 }, /* N  */
4104 
4105         {0.,        0.,        .5  }, /* O  */
4106         {1.,        1.,        .5  }, /* P  */
4107         {gamma,     1 - gamma, .5  }, /* Q  */
4108         {1 + gamma, gamma,     .5  }, /* R  */
4109         {2 - gamma, 1 + gamma, .5  }, /* S  */
4110         {1 - gamma, 2 - gamma, .5  }, /* T  */
4111 
4112         {0.,        .5,        .75 }, /* U  */
4113         {0.,        1.5,       .75 }, /* V  */
4114         {1.,        .5,        .75 }, /* W  */
4115         {1.,        1.5,       .75 }, /* X  */
4116         {.5,        .75,       .75 }, /* Y  */
4117         {.5,        1.75,      .75 }, /* Z  */
4118         {1.5,       .25,       .75 }, /* Ap */
4119         {1.5,       1.25,      .75 }, /* Bp */
4120 
4121         {1.,        0.,        1.  }, /* Cp */
4122         {0.,        1.,        1.  }, /* Dp */
4123         {1 - gamma, 1 - gamma, 1.  }, /* Ep */
4124         {1 + gamma, 1 + gamma, 1.  }, /* Fp */
4125         {2 - gamma, gamma,     1.  }, /* Gp */
4126         {gamma,     2 - gamma, 1.  }, /* Hp */
4127 
4128         {.5,        0.,        1.25}, /* Ip */
4129         {1.5,       0.,        1.25}, /* Jp */
4130         {.5,        1.,        1.25}, /* Kp */
4131         {1.5,       1.,        1.25}, /* Lp */
4132         {.75,       .5,        1.25}, /* Mp */
4133         {1.75,      .5,        1.25}, /* Np */
4134         {.25,       1.5,       1.25}, /* Op */
4135         {1.25,      1.5,       1.25}, /* Pp */
4136 
4137         {0.,        0.,        1.5 }, /* Qp */
4138         {1.,        1.,        1.5 }, /* Rp */
4139         {1 - gamma, gamma,     1.5 }, /* Sp */
4140         {2 - gamma, 1 - gamma, 1.5 }, /* Tp */
4141         {1 + gamma, 2 - gamma, 1.5 }, /* Up */
4142         {gamma,     1 + gamma, 1.5 }, /* Vp */
4143 
4144         {0.,        .5,        1.75}, /* Wp */
4145         {0.,        1.5,       1.75}, /* Xp */
4146         {1.,        .5,        1.75}, /* Yp */
4147         {1.,        1.5,       1.75}, /* Zp */
4148         {.5,        .25,       1.75}, /* Aq */
4149         {.5,        1.25,      1.75}, /* Bq */
4150         {1.5,       .75,       1.75}, /* Cq */
4151         {1.5,       1.75,      1.75}, /* Dq */
4152       };
4153       PetscInt (*cells)[64][4] = NULL;
4154       PetscBool *seen;
4155       PetscInt  *vertToTrueVert;
4156       PetscInt   count;
4157 
4158       for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1;
4159       numBlocks = 1;
4160       for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i];
4161       numBlocksPlus = 1;
4162       for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i];
4163       numFaces = numBlocks * facesPerBlock;
4164       PetscCall(PetscMalloc1(numBlocks, &cells));
4165       PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen));
4166       for (PetscInt k = 0; k < extent[2]; k++) {
4167         for (PetscInt j = 0; j < extent[1]; j++) {
4168           for (PetscInt i = 0; i < extent[0]; i++) {
4169             for (PetscInt f = 0; f < facesPerBlock; f++) {
4170               for (PetscInt v = 0; v < 4; v++) {
4171                 PetscInt vertRaw     = pattern[f][v];
4172                 PetscInt blockidx    = vertRaw / 56;
4173                 PetscInt patternvert = vertRaw % 56;
4174                 PetscInt xplus       = (blockidx & 1);
4175                 PetscInt yplus       = (blockidx & 2) >> 1;
4176                 PetscInt zplus       = (blockidx & 4) >> 2;
4177                 PetscInt zcoord      = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus);
4178                 PetscInt ycoord      = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus);
4179                 PetscInt xcoord      = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus);
4180                 PetscInt vert        = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert;
4181 
4182                 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert;
4183                 seen[vert]                                       = PETSC_TRUE;
4184               }
4185             }
4186           }
4187         }
4188       }
4189       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++)
4190         if (seen[i]) numVertices++;
4191       count = 0;
4192       PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert));
4193       PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords));
4194       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1;
4195       for (PetscInt k = 0; k < extentPlus[2]; k++) {
4196         for (PetscInt j = 0; j < extentPlus[1]; j++) {
4197           for (PetscInt i = 0; i < extentPlus[0]; i++) {
4198             for (PetscInt v = 0; v < vertsPerBlock; v++) {
4199               PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v;
4200 
4201               if (seen[vIdx]) {
4202                 PetscInt thisVert;
4203 
4204                 vertToTrueVert[vIdx] = thisVert = count++;
4205 
4206                 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d];
4207                 vtxCoords[3 * thisVert + 0] += i * 2;
4208                 vtxCoords[3 * thisVert + 1] += j * 2;
4209                 vtxCoords[3 * thisVert + 2] += k * 2;
4210               }
4211             }
4212           }
4213         }
4214       }
4215       for (PetscInt i = 0; i < numBlocks; i++) {
4216         for (PetscInt f = 0; f < facesPerBlock; f++) {
4217           for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]];
4218         }
4219       }
4220       PetscCall(PetscFree(vertToTrueVert));
4221       PetscCall(PetscFree(seen));
4222       cells_flat = cells[0][0];
4223       numEdges   = 0;
4224       for (PetscInt i = 0; i < numFaces; i++) {
4225         for (PetscInt e = 0; e < 4; e++) {
4226           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
4227           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};
4228 
4229           for (PetscInt d = 0; d < 3; d++) {
4230             if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) {
4231               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++;
4232               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++;
4233             }
4234           }
4235         }
4236       }
4237       PetscCall(PetscMalloc1(numEdges, &edges));
4238       PetscCall(PetscMalloc1(numEdges, &edgeSets));
4239       for (PetscInt edge = 0, i = 0; i < numFaces; i++) {
4240         for (PetscInt e = 0; e < 4; e++) {
4241           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
4242           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};
4243 
4244           for (PetscInt d = 0; d < 3; d++) {
4245             if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) {
4246               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) {
4247                 edges[edge][0]   = ev[0];
4248                 edges[edge][1]   = ev[1];
4249                 edgeSets[edge++] = 2 * d;
4250               }
4251               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) {
4252                 edges[edge][0]   = ev[0];
4253                 edges[edge][1]   = ev[1];
4254                 edgeSets[edge++] = 2 * d + 1;
4255               }
4256             }
4257           }
4258         }
4259       }
4260     }
4261     evalFunc   = TPSEvaluate_Gyroid;
4262     normalFunc = TPSExtrudeNormalFunc_Gyroid;
4263     break;
4264   }
4265 
4266   PetscCall(DMSetDimension(dm, topoDim));
4267   if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat));
4268   else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL));
4269   PetscCall(PetscFree(cells_flat));
4270   {
4271     DM idm;
4272     PetscCall(DMPlexInterpolate(dm, &idm));
4273     PetscCall(DMPlexReplace_Internal(dm, &idm));
4274   }
4275   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords));
4276   else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL));
4277   PetscCall(PetscFree(vtxCoords));
4278 
4279   PetscCall(DMCreateLabel(dm, "Face Sets"));
4280   PetscCall(DMGetLabel(dm, "Face Sets", &label));
4281   for (PetscInt e = 0; e < numEdges; e++) {
4282     PetscInt        njoin;
4283     const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]};
4284     PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join));
4285     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]);
4286     PetscCall(DMLabelSetValue(label, join[0], edgeSets[e]));
4287     PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join));
4288   }
4289   PetscCall(PetscFree(edges));
4290   PetscCall(PetscFree(edgeSets));
4291   if (tps_distribute) {
4292     DM               pdm = NULL;
4293     PetscPartitioner part;
4294 
4295     PetscCall(DMPlexGetPartitioner(dm, &part));
4296     PetscCall(PetscPartitionerSetFromOptions(part));
4297     PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm));
4298     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
4299     // Do not auto-distribute again
4300     PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
4301   }
4302 
4303   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4304   for (PetscInt refine = 0; refine < refinements; refine++) {
4305     PetscInt     m;
4306     DM           dmf, cdm, cdmf;
4307     Vec          X;
4308     PetscScalar *x;
4309 
4310     PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf));
4311     PetscCall(DMGetCoordinateDM(dm, &cdm));
4312     PetscCall(DMGetCoordinateDM(dmf, &cdmf));
4313     PetscCall(DMCopyDisc(cdm, cdmf));
4314     PetscCall(DMPlexReplace_Internal(dm, &dmf));
4315 
4316     PetscCall(DMGetCoordinatesLocal(dm, &X));
4317     PetscCall(VecGetLocalSize(X, &m));
4318     PetscCall(VecGetArray(X, &x));
4319     for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i]));
4320     PetscCall(VecRestoreArray(X, &x));
4321   }
4322 
4323   // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices.
4324   PetscCall(DMGetLabel(dm, "Face Sets", &label));
4325   PetscCall(DMPlexLabelComplete(dm, label));
4326 
4327   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
4328 
4329   if (thickness > 0) {
4330     DM              edm, cdm, ecdm;
4331     DMPlexTransform tr;
4332     const char     *prefix;
4333     PetscOptions    options;
4334     // Code from DMPlexExtrude
4335     PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
4336     PetscCall(DMPlexTransformSetDM(tr, dm));
4337     PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDETYPE));
4338     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
4339     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
4340     PetscCall(PetscObjectGetOptions((PetscObject)dm, &options));
4341     PetscCall(PetscObjectSetOptions((PetscObject)tr, options));
4342     PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers));
4343     PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness));
4344     PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE));
4345     PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE));
4346     PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc));
4347     PetscCall(DMPlexTransformSetFromOptions(tr));
4348     PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL));
4349     PetscCall(DMPlexTransformSetUp(tr));
4350     PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view"));
4351     PetscCall(DMPlexTransformApply(tr, dm, &edm));
4352     PetscCall(DMCopyDisc(dm, edm));
4353     PetscCall(DMGetCoordinateDM(dm, &cdm));
4354     PetscCall(DMGetCoordinateDM(edm, &ecdm));
4355     PetscCall(DMCopyDisc(cdm, ecdm));
4356     PetscCall(DMPlexTransformCreateDiscLabels(tr, edm));
4357     PetscCall(DMPlexTransformDestroy(&tr));
4358     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, edm));
4359     PetscCall(DMPlexReplace_Internal(dm, &edm));
4360   }
4361   PetscFunctionReturn(PETSC_SUCCESS);
4362 }
4363 
4364 /*@
4365   DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface
4366 
4367   Collective
4368 
4369   Input Parameters:
4370 + comm           - The communicator for the `DM` object
4371 . tpstype        - Type of triply-periodic surface
4372 . extent         - Array of length 3 containing number of periods in each direction
4373 . periodic       - array of length 3 with periodicity, or `NULL` for non-periodic
4374 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable)
4375 . refinements    - Number of factor-of-2 refinements of 2D manifold mesh
4376 . layers         - Number of cell layers extruded in normal direction
4377 - thickness      - Thickness in normal direction
4378 
4379   Output Parameter:
4380 . dm - The `DM` object
4381 
4382   Level: beginner
4383 
4384   Notes:
4385   This meshes the surface of the Schwarz P or Gyroid surfaces.  Schwarz P is the simplest member of the triply-periodic minimal surfaces.
4386   <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries.
4387   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.
4388   Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested.
4389   On each refinement, all vertices are projected to their nearest point on the surface.
4390   This projection could readily be extended to related surfaces.
4391 
4392   See {cite}`maskery2018insights`
4393 
4394   The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$.
4395   When the mesh is refined, "Face Sets" contain the new vertices (created during refinement).
4396   Use `DMPlexLabelComplete()` to propagate to coarse-level vertices.
4397 
4398   Developer Notes:
4399   The Gyroid mesh does not currently mark boundary sets.
4400 
4401 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()`
4402 @*/
DMPlexCreateTPSMesh(MPI_Comm comm,DMPlexTPSType tpstype,const PetscInt extent[],const DMBoundaryType periodic[],PetscBool tps_distribute,PetscInt refinements,PetscInt layers,PetscReal thickness,DM * dm)4403 PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm)
4404 {
4405   PetscFunctionBegin;
4406   PetscCall(DMCreate(comm, dm));
4407   PetscCall(DMSetType(*dm, DMPLEX));
4408   PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness));
4409   PetscFunctionReturn(PETSC_SUCCESS);
4410 }
4411 
4412 /*@
4413   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.
4414 
4415   Collective
4416 
4417   Input Parameters:
4418 + comm    - The communicator for the `DM` object
4419 . dim     - The dimension
4420 . simplex - Use simplices, or tensor product cells
4421 - R       - The radius
4422 
4423   Output Parameter:
4424 . dm - The `DM` object
4425 
4426   Level: beginner
4427 
4428 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
4429 @*/
DMPlexCreateSphereMesh(MPI_Comm comm,PetscInt dim,PetscBool simplex,PetscReal R,DM * dm)4430 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm)
4431 {
4432   PetscFunctionBegin;
4433   PetscAssertPointer(dm, 5);
4434   PetscCall(DMCreate(comm, dm));
4435   PetscCall(DMSetType(*dm, DMPLEX));
4436   PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R));
4437   PetscFunctionReturn(PETSC_SUCCESS);
4438 }
4439 
DMPlexCreateBallMesh_Internal(DM dm,PetscInt dim,PetscReal R)4440 static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R)
4441 {
4442   DM          sdm, vol;
4443   DMLabel     bdlabel;
4444   const char *prefix;
4445 
4446   PetscFunctionBegin;
4447   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
4448   PetscCall(DMSetType(sdm, DMPLEX));
4449   PetscCall(DMGetOptionsPrefix(dm, &prefix));
4450   PetscCall(DMSetOptionsPrefix(sdm, prefix));
4451   PetscCall(DMAppendOptionsPrefix(sdm, "bd_"));
4452   PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE));
4453   PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R));
4454   PetscCall(DMSetFromOptions(sdm));
4455   PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view"));
4456   PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol));
4457   PetscCall(DMDestroy(&sdm));
4458   PetscCall(DMPlexReplace_Internal(dm, &vol));
4459   PetscCall(DMCreateLabel(dm, "marker"));
4460   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
4461   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
4462   PetscCall(DMPlexLabelComplete(dm, bdlabel));
4463   PetscFunctionReturn(PETSC_SUCCESS);
4464 }
4465 
4466 /*@
4467   DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d.
4468 
4469   Collective
4470 
4471   Input Parameters:
4472 + comm - The communicator for the `DM` object
4473 . dim  - The dimension
4474 - R    - The radius
4475 
4476   Output Parameter:
4477 . dm - The `DM` object
4478 
4479   Options Database Key:
4480 . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry
4481 
4482   Level: beginner
4483 
4484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
4485 @*/
DMPlexCreateBallMesh(MPI_Comm comm,PetscInt dim,PetscReal R,DM * dm)4486 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm)
4487 {
4488   PetscFunctionBegin;
4489   PetscCall(DMCreate(comm, dm));
4490   PetscCall(DMSetType(*dm, DMPLEX));
4491   PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R));
4492   PetscFunctionReturn(PETSC_SUCCESS);
4493 }
4494 
DMPlexCreateReferenceCell_Internal(DM rdm,DMPolytopeType ct)4495 static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct)
4496 {
4497   PetscFunctionBegin;
4498   switch (ct) {
4499   case DM_POLYTOPE_POINT: {
4500     PetscInt    numPoints[1]        = {1};
4501     PetscInt    coneSize[1]         = {0};
4502     PetscInt    cones[1]            = {0};
4503     PetscInt    coneOrientations[1] = {0};
4504     PetscScalar vertexCoords[1]     = {0.0};
4505 
4506     PetscCall(DMSetDimension(rdm, 0));
4507     PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4508   } break;
4509   case DM_POLYTOPE_SEGMENT: {
4510     PetscInt    numPoints[2]        = {2, 1};
4511     PetscInt    coneSize[3]         = {2, 0, 0};
4512     PetscInt    cones[2]            = {1, 2};
4513     PetscInt    coneOrientations[2] = {0, 0};
4514     PetscScalar vertexCoords[2]     = {-1.0, 1.0};
4515 
4516     PetscCall(DMSetDimension(rdm, 1));
4517     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4518   } break;
4519   case DM_POLYTOPE_POINT_PRISM_TENSOR: {
4520     PetscInt    numPoints[2]        = {2, 1};
4521     PetscInt    coneSize[3]         = {2, 0, 0};
4522     PetscInt    cones[2]            = {1, 2};
4523     PetscInt    coneOrientations[2] = {0, 0};
4524     PetscScalar vertexCoords[2]     = {-1.0, 1.0};
4525 
4526     PetscCall(DMSetDimension(rdm, 1));
4527     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4528   } break;
4529   case DM_POLYTOPE_TRIANGLE: {
4530     PetscInt    numPoints[2]        = {3, 1};
4531     PetscInt    coneSize[4]         = {3, 0, 0, 0};
4532     PetscInt    cones[3]            = {1, 2, 3};
4533     PetscInt    coneOrientations[3] = {0, 0, 0};
4534     PetscScalar vertexCoords[6]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0};
4535 
4536     PetscCall(DMSetDimension(rdm, 2));
4537     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4538   } break;
4539   case DM_POLYTOPE_QUADRILATERAL: {
4540     PetscInt    numPoints[2]        = {4, 1};
4541     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
4542     PetscInt    cones[4]            = {1, 2, 3, 4};
4543     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
4544     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0};
4545 
4546     PetscCall(DMSetDimension(rdm, 2));
4547     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4548   } break;
4549   case DM_POLYTOPE_SEG_PRISM_TENSOR: {
4550     PetscInt    numPoints[2]        = {4, 1};
4551     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
4552     PetscInt    cones[4]            = {1, 2, 3, 4};
4553     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
4554     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
4555 
4556     PetscCall(DMSetDimension(rdm, 2));
4557     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4558   } break;
4559   case DM_POLYTOPE_TETRAHEDRON: {
4560     PetscInt    numPoints[2]        = {4, 1};
4561     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
4562     PetscInt    cones[4]            = {1, 2, 3, 4};
4563     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
4564     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};
4565 
4566     PetscCall(DMSetDimension(rdm, 3));
4567     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4568   } break;
4569   case DM_POLYTOPE_HEXAHEDRON: {
4570     PetscInt    numPoints[2]        = {8, 1};
4571     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
4572     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
4573     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
4574     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};
4575 
4576     PetscCall(DMSetDimension(rdm, 3));
4577     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4578   } break;
4579   case DM_POLYTOPE_TRI_PRISM: {
4580     PetscInt    numPoints[2]        = {6, 1};
4581     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
4582     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
4583     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
4584     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};
4585 
4586     PetscCall(DMSetDimension(rdm, 3));
4587     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4588   } break;
4589   case DM_POLYTOPE_TRI_PRISM_TENSOR: {
4590     PetscInt    numPoints[2]        = {6, 1};
4591     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
4592     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
4593     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
4594     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};
4595 
4596     PetscCall(DMSetDimension(rdm, 3));
4597     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4598   } break;
4599   case DM_POLYTOPE_QUAD_PRISM_TENSOR: {
4600     PetscInt    numPoints[2]        = {8, 1};
4601     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
4602     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
4603     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
4604     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};
4605 
4606     PetscCall(DMSetDimension(rdm, 3));
4607     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4608   } break;
4609   case DM_POLYTOPE_PYRAMID: {
4610     PetscInt    numPoints[2]        = {5, 1};
4611     PetscInt    coneSize[6]         = {5, 0, 0, 0, 0, 0};
4612     PetscInt    cones[5]            = {1, 2, 3, 4, 5};
4613     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
4614     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};
4615 
4616     PetscCall(DMSetDimension(rdm, 3));
4617     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4618   } break;
4619   default:
4620     SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]);
4621   }
4622   {
4623     PetscInt Nv, v;
4624 
4625     /* Must create the celltype label here so that we do not automatically try to compute the types */
4626     PetscCall(DMCreateLabel(rdm, "celltype"));
4627     PetscCall(DMPlexSetCellType(rdm, 0, ct));
4628     PetscCall(DMPlexGetChart(rdm, NULL, &Nv));
4629     for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT));
4630   }
4631   PetscCall(DMPlexInterpolateInPlace_Internal(rdm));
4632   PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct]));
4633   PetscFunctionReturn(PETSC_SUCCESS);
4634 }
4635 
4636 /*@
4637   DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell
4638 
4639   Collective
4640 
4641   Input Parameters:
4642 + comm - The communicator
4643 - ct   - The cell type of the reference cell
4644 
4645   Output Parameter:
4646 . refdm - The reference cell
4647 
4648   Level: intermediate
4649 
4650 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`
4651 @*/
DMPlexCreateReferenceCell(MPI_Comm comm,DMPolytopeType ct,DM * refdm)4652 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm)
4653 {
4654   PetscFunctionBegin;
4655   PetscCall(DMCreate(comm, refdm));
4656   PetscCall(DMSetType(*refdm, DMPLEX));
4657   PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct));
4658   PetscFunctionReturn(PETSC_SUCCESS);
4659 }
4660 
DMPlexCreateBoundaryLabel_Private(DM dm,const char name[])4661 static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[])
4662 {
4663   DM        plex;
4664   DMLabel   label;
4665   PetscBool hasLabel;
4666 
4667   PetscFunctionBegin;
4668   PetscCall(DMHasLabel(dm, name, &hasLabel));
4669   if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS);
4670   PetscCall(DMCreateLabel(dm, name));
4671   PetscCall(DMGetLabel(dm, name, &label));
4672   PetscCall(DMConvert(dm, DMPLEX, &plex));
4673   PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label));
4674   PetscCall(DMPlexLabelComplete(plex, label));
4675   PetscCall(DMDestroy(&plex));
4676   PetscFunctionReturn(PETSC_SUCCESS);
4677 }
4678 
4679 /*
4680   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.
4681 
4682     (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0]))
4683 */
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[])4684 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[])
4685 {
4686   const PetscReal low = PetscRealPart(constants[0]);
4687   const PetscReal upp = PetscRealPart(constants[1]);
4688   const PetscReal r   = PetscRealPart(u[1]);
4689   const PetscReal th  = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low);
4690 
4691   f0[0] = r * PetscCosReal(th);
4692   f0[1] = r * PetscSinReal(th);
4693 }
4694 
4695 // Insert vertices and their joins, marked by depth
ProcessCohesiveLabel_Vertices(DM dm,DMLabel label,DMLabel vlabel,PetscInt val,PetscInt n,const PetscInt vertices[])4696 static PetscErrorCode ProcessCohesiveLabel_Vertices(DM dm, DMLabel label, DMLabel vlabel, PetscInt val, PetscInt n, const PetscInt vertices[])
4697 {
4698   PetscFunctionBegin;
4699   PetscCall(DMPlexMarkSubmesh_Interpolated(dm, vlabel, val, PETSC_FALSE, PETSC_FALSE, label, NULL));
4700   PetscFunctionReturn(PETSC_SUCCESS);
4701 }
4702 
4703 // Insert faces and their closures, marked by depth
ProcessCohesiveLabel_Faces(DM dm,DMLabel label,PetscInt n,const PetscInt faces[])4704 static PetscErrorCode ProcessCohesiveLabel_Faces(DM dm, DMLabel label, PetscInt n, const PetscInt faces[])
4705 {
4706   PetscFunctionBegin;
4707   for (PetscInt p = 0; p < n; ++p) {
4708     const PetscInt point   = faces[p];
4709     PetscInt      *closure = NULL;
4710     PetscInt       clSize, pdepth;
4711 
4712     PetscCall(DMPlexGetPointDepth(dm, point, &pdepth));
4713     PetscCall(DMLabelSetValue(label, point, pdepth));
4714     PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
4715     for (PetscInt cl = 0; cl < clSize * 2; cl += 2) {
4716       PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth));
4717       PetscCall(DMLabelSetValue(label, closure[cl], pdepth));
4718     }
4719     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
4720   }
4721   PetscFunctionReturn(PETSC_SUCCESS);
4722 }
4723 
4724 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg);
4725 
4726 const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL};
4727 
DMPlexCreateFromOptions_Internal(PetscOptionItems PetscOptionsObject,PetscBool * useCoordSpace,DM dm)4728 static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems PetscOptionsObject, PetscBool *useCoordSpace, DM dm)
4729 {
4730   DMPlexShape    shape   = DM_SHAPE_BOX;
4731   DMPolytopeType cell    = DM_POLYTOPE_TRIANGLE;
4732   PetscInt       dim     = 2;
4733   PetscBool      simplex = PETSC_TRUE, interpolate = PETSC_TRUE, orient = PETSC_FALSE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE;
4734   PetscBool      flg, flg2, fflg, strflg, bdfflg, nameflg;
4735   MPI_Comm       comm;
4736   char           filename[PETSC_MAX_PATH_LEN]   = "<unspecified>";
4737   char           bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>";
4738   char           plexname[PETSC_MAX_PATH_LEN]   = "";
4739   const char    *option;
4740 
4741   PetscFunctionBegin;
4742   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
4743   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4744   /* TODO Turn this into a registration interface */
4745   PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg));
4746   PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg));
4747   PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg));
4748   PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg));
4749   PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL));
4750   PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL));
4751   PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg));
4752   PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0));
4753   PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg));
4754   PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg));
4755   PetscCall(PetscOptionsBool("-dm_plex_orient", "Orient the constructed mesh", "DMPlexOrient", orient, &orient, &flg));
4756   PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg));
4757   PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2));
4758   if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure));
4759   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_adj", "Debug output level all adjacency computations", "", 0, &((DM_Plex *)dm->data)->printAdj, NULL, 0));
4760 
4761   switch (cell) {
4762   case DM_POLYTOPE_POINT:
4763   case DM_POLYTOPE_SEGMENT:
4764   case DM_POLYTOPE_POINT_PRISM_TENSOR:
4765   case DM_POLYTOPE_TRIANGLE:
4766   case DM_POLYTOPE_QUADRILATERAL:
4767   case DM_POLYTOPE_TETRAHEDRON:
4768   case DM_POLYTOPE_HEXAHEDRON:
4769     *useCoordSpace = PETSC_TRUE;
4770     break;
4771   default:
4772     *useCoordSpace = PETSC_FALSE;
4773     break;
4774   }
4775 
4776   if (fflg) {
4777     DM          dmnew;
4778     const char *name;
4779 
4780     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
4781     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, nameflg ? plexname : name, interpolate, &dmnew));
4782     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4783     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4784   } else if (refDomain) {
4785     PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell));
4786   } else if (bdfflg) {
4787     DM          bdm, dmnew;
4788     const char *name;
4789 
4790     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
4791     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, nameflg ? plexname : name, interpolate, &bdm));
4792     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_"));
4793     PetscCall(DMSetFromOptions(bdm));
4794     PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew));
4795     PetscCall(DMDestroy(&bdm));
4796     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4797     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4798   } else if (strflg) {
4799     DM          dmnew;
4800     PetscViewer viewer;
4801     const char *contents;
4802     char       *strname;
4803     char        tmpdir[PETSC_MAX_PATH_LEN];
4804     char        tmpfilename[PETSC_MAX_PATH_LEN];
4805     char        name[PETSC_MAX_PATH_LEN];
4806     MPI_Comm    comm;
4807     PetscMPIInt rank;
4808 
4809     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4810     PetscCallMPI(MPI_Comm_rank(comm, &rank));
4811     PetscCall(PetscStrchr(filename, ':', &strname));
4812     PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename);
4813     strname[0] = '\0';
4814     ++strname;
4815     PetscCall(PetscDLSym(NULL, strname, (void **)&contents));
4816     PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname);
4817     PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN));
4818     PetscCall(PetscStrlcat(tmpdir, "/meshXXXXXX", PETSC_MAX_PATH_LEN));
4819     PetscCall(PetscMkdtemp(tmpdir));
4820     PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh.%s", tmpdir, filename));
4821     PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer));
4822     PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents));
4823     PetscCall(PetscViewerDestroy(&viewer));
4824     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew));
4825     PetscCall(PetscRMTree(tmpdir));
4826     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname));
4827     PetscCall(PetscObjectSetName((PetscObject)dm, name));
4828     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4829     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4830   } else {
4831     PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape]));
4832     switch (shape) {
4833     case DM_SHAPE_BOX:
4834     case DM_SHAPE_ZBOX:
4835     case DM_SHAPE_ANNULUS: {
4836       PetscInt       faces[3]  = {0, 0, 0};
4837       PetscReal      lower[3]  = {0, 0, 0};
4838       PetscReal      upper[3]  = {1, 1, 1};
4839       DMBoundaryType bdt[3]    = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
4840       PetscBool      isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE;
4841       PetscInt       i, n;
4842 
4843       n = dim;
4844       for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim);
4845       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
4846       n = 3;
4847       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4848       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4849       n = 3;
4850       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4851       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4852       n = 3;
4853       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
4854       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4855 
4856       PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented");
4857       if (isAnnular)
4858         for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC;
4859 
4860       switch (cell) {
4861       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4862         PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt));
4863         if (!interpolate) {
4864           DM udm;
4865 
4866           PetscCall(DMPlexUninterpolate(dm, &udm));
4867           PetscCall(DMPlexReplace_Internal(dm, &udm));
4868         }
4869         break;
4870       default:
4871         PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate));
4872         break;
4873       }
4874       if (isAnnular) {
4875         DM          cdm;
4876         PetscDS     cds;
4877         PetscScalar bounds[2] = {lower[0], upper[0]};
4878 
4879         // Fix coordinates for annular region
4880         PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
4881         PetscCall(DMSetCellCoordinatesLocal(dm, NULL));
4882         PetscCall(DMSetCellCoordinates(dm, NULL));
4883         PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_FALSE, PETSC_TRUE));
4884         PetscCall(DMGetCoordinateDM(dm, &cdm));
4885         PetscCall(DMGetDS(cdm, &cds));
4886         PetscCall(PetscDSSetConstants(cds, 2, bounds));
4887         PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus));
4888       }
4889     } break;
4890     case DM_SHAPE_BOX_SURFACE: {
4891       PetscInt  faces[3] = {0, 0, 0};
4892       PetscReal lower[3] = {0, 0, 0};
4893       PetscReal upper[3] = {1, 1, 1};
4894       PetscInt  i, n;
4895 
4896       n = dim + 1;
4897       for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1));
4898       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
4899       n = 3;
4900       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4901       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);
4902       n = 3;
4903       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4904       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);
4905       PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate));
4906     } break;
4907     case DM_SHAPE_SPHERE: {
4908       PetscReal R = 1.0;
4909 
4910       PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg));
4911       PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R));
4912     } break;
4913     case DM_SHAPE_BALL: {
4914       PetscReal R = 1.0;
4915 
4916       PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg));
4917       PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R));
4918     } break;
4919     case DM_SHAPE_CYLINDER: {
4920       DMBoundaryType bdt = DM_BOUNDARY_NONE;
4921       PetscInt       Nw  = 6;
4922       PetscInt       Nr  = 0;
4923 
4924       PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL));
4925       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL));
4926       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_refine", "Number of refinements before projection", "", Nr, &Nr, NULL));
4927       switch (cell) {
4928       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4929         PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate));
4930         break;
4931       default:
4932         PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt, Nr));
4933         break;
4934       }
4935     } break;
4936     case DM_SHAPE_SCHWARZ_P: // fallthrough
4937     case DM_SHAPE_GYROID: {
4938       PetscInt       extent[3] = {1, 1, 1}, refine = 0, layers = 0, three;
4939       PetscReal      thickness   = 0.;
4940       DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
4941       DMPlexTPSType  tps_type    = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID;
4942       PetscBool      tps_distribute;
4943       PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL));
4944       PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL));
4945       PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL));
4946       PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL));
4947       PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL));
4948       PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute));
4949       PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL));
4950       PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness));
4951     } break;
4952     case DM_SHAPE_DOUBLET: {
4953       DM        dmnew;
4954       PetscReal rl = 0.0;
4955 
4956       PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL));
4957       PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew));
4958       PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4959       PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4960     } break;
4961     case DM_SHAPE_HYPERCUBIC: {
4962       PetscInt       *edges, overlap = 1;
4963       PetscReal      *lower, *upper;
4964       DMBoundaryType *bdt;
4965       PetscInt        n, d;
4966 
4967       *useCoordSpace = PETSC_FALSE;
4968       PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt));
4969       for (d = 0; d < dim; ++d) {
4970         edges[d] = 1;
4971         lower[d] = 0.;
4972         upper[d] = 1.;
4973         bdt[d]   = DM_BOUNDARY_PERIODIC;
4974       }
4975       n = dim;
4976       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg));
4977       n = dim;
4978       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4979       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4980       n = dim;
4981       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4982       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4983       n = dim;
4984       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
4985       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4986       PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", overlap, &overlap, NULL, 0));
4987       PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, overlap, bdt));
4988       PetscCall(PetscFree4(edges, lower, upper, bdt));
4989     } break;
4990     default:
4991       SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]);
4992     }
4993   }
4994   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4995   if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname));
4996   if (orient) PetscCall(DMPlexOrient(dm));
4997   // Allow label creation
4998   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg));
4999   if (flg) {
5000     DMLabel     label;
5001     PetscInt   *points, cStart, cEnd, n;
5002     char        fulloption[PETSC_MAX_PATH_LEN];
5003     const char *name = &option[14];
5004 
5005     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5006     n = PetscMax(cEnd - cStart, 1024);
5007     PetscCall(PetscMalloc1(n, &points));
5008     PetscCall(DMCreateLabel(dm, name));
5009     PetscCall(DMGetLabel(dm, name, &label));
5010     fulloption[0] = '-';
5011     fulloption[1] = 0;
5012     PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN));
5013     PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL));
5014     for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1));
5015     PetscCall(PetscFree(points));
5016   }
5017   // Allow cohesive label creation
5018   //   Faces are input, completed, and all points are marked with their depth
5019   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg));
5020   if (flg) {
5021     DMLabel   label;
5022     PetscInt  points[1024], n, pStart, pEnd, Nl = 1;
5023     PetscBool noCreate = PETSC_FALSE;
5024     char      fulloption[PETSC_MAX_PATH_LEN];
5025     char      name[PETSC_MAX_PATH_LEN];
5026     size_t    len;
5027 
5028     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5029     PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN));
5030     PetscCall(PetscStrlen(name, &len));
5031     if (name[len - 1] == '0') Nl = 10;
5032     for (PetscInt l = 0; l < Nl; ++l) {
5033       if (l > 0) name[len - 1] = (char)('0' + l);
5034       fulloption[0] = 0;
5035       PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32));
5036       PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32));
5037       n = 1024;
5038       PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg));
5039       if (!flg) break;
5040       PetscCall(DMHasLabel(dm, name, &noCreate));
5041       if (noCreate) {
5042         DMLabel         inlabel;
5043         IS              pointIS;
5044         const PetscInt *lpoints;
5045         PetscInt        pdep, ln, inval = points[0];
5046         char            newname[PETSC_MAX_PATH_LEN];
5047 
5048         PetscCheck(n == 1, comm, PETSC_ERR_ARG_WRONG, "Must specify a label value with this option");
5049         PetscCall(DMGetLabel(dm, name, &inlabel));
5050         PetscCall(DMLabelGetStratumIS(inlabel, inval, &pointIS));
5051         PetscCall(ISGetLocalSize(pointIS, &ln));
5052         PetscCall(ISGetIndices(pointIS, &lpoints));
5053         PetscCall(DMPlexGetPointDepth(dm, lpoints[0], &pdep));
5054         PetscCall(PetscSNPrintf(newname, PETSC_MAX_PATH_LEN, "%s%" PetscInt_FMT, name, points[0]));
5055         PetscCall(DMCreateLabel(dm, newname));
5056         PetscCall(DMGetLabel(dm, newname, &label));
5057         if (!pdep) PetscCall(ProcessCohesiveLabel_Vertices(dm, label, inlabel, inval, ln, lpoints));
5058         else PetscCall(ProcessCohesiveLabel_Faces(dm, label, ln, lpoints));
5059         PetscCall(ISRestoreIndices(pointIS, &lpoints));
5060         PetscCall(ISDestroy(&pointIS));
5061       } else {
5062         PetscCall(DMCreateLabel(dm, name));
5063         PetscCall(DMGetLabel(dm, name, &label));
5064         if (pStart >= pEnd) n = 0;
5065         PetscCall(ProcessCohesiveLabel_Faces(dm, label, n, points));
5066       }
5067       PetscCall(DMPlexOrientLabel(dm, label));
5068       PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL));
5069     }
5070   }
5071   PetscCall(DMViewFromOptions(dm, NULL, "-created_dm_view"));
5072   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
5073   PetscFunctionReturn(PETSC_SUCCESS);
5074 }
5075 
DMSetFromOptions_NonRefinement_Plex(DM dm,PetscOptionItems PetscOptionsObject)5076 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems PetscOptionsObject)
5077 {
5078   DM_Plex  *mesh = (DM_Plex *)dm->data;
5079   PetscBool flg, flg2;
5080   char      bdLabel[PETSC_MAX_PATH_LEN];
5081   char      method[PETSC_MAX_PATH_LEN];
5082 
5083   PetscFunctionBegin;
5084   /* Handle viewing */
5085   PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL));
5086   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0));
5087   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0));
5088   PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL));
5089   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0));
5090   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0));
5091   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_project", "Debug output level all projection computations", "DMPlexProject", 0, &mesh->printProject, NULL, 0));
5092   PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg));
5093   if (flg) PetscCall(PetscLogDefaultBegin());
5094   // Interpolation
5095   PetscCall(PetscOptionsBool("-dm_plex_interpolate_prefer_tensor", "When different orderings exist, prefer the tensor order", "DMPlexSetInterpolationPreferTensor", mesh->interpolatePreferTensor, &mesh->interpolatePreferTensor, NULL));
5096   /* Labeling */
5097   PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", NULL, bdLabel, sizeof(bdLabel), &flg));
5098   if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel));
5099   /* Point Location */
5100   PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL));
5101   /* Partitioning and distribution */
5102   PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL));
5103   /* Reordering */
5104   PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg));
5105   if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE));
5106   PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", NULL, method, PETSC_MAX_PATH_LEN, &flg));
5107   if (flg) PetscCall(DMReorderSectionSetType(dm, method));
5108   /* Generation and remeshing */
5109   PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL));
5110   PetscCall(PetscOptionsBool("-dm_plex_save_transform", "Save the transform producing this mesh", "DMAdapt", PETSC_FALSE, &mesh->saveTransform, NULL));
5111   /* Projection behavior */
5112   PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0));
5113   PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL));
5114   /* Checking structure */
5115   {
5116     PetscBool all = PETSC_FALSE;
5117 
5118     PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL));
5119     if (all) {
5120       PetscCall(DMPlexCheck(dm));
5121     } else {
5122       PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2));
5123       if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm));
5124       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));
5125       if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0));
5126       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));
5127       if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0));
5128       PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2));
5129       if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm));
5130       PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2));
5131       if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
5132       PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2));
5133       if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm));
5134     }
5135     PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2));
5136     if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE));
5137   }
5138   {
5139     PetscReal scale = 1.0;
5140 
5141     PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg));
5142     if (flg) {
5143       Vec coordinates, coordinatesLocal;
5144 
5145       PetscCall(DMGetCoordinates(dm, &coordinates));
5146       PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
5147       PetscCall(VecScale(coordinates, scale));
5148       PetscCall(VecScale(coordinatesLocal, scale));
5149     }
5150   }
5151   PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner));
5152   PetscFunctionReturn(PETSC_SUCCESS);
5153 }
5154 
DMSetFromOptions_Overlap_Plex(DM dm,PetscOptionItems PetscOptionsObject,PetscInt * overlap)5155 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems PetscOptionsObject, PetscInt *overlap)
5156 {
5157   PetscInt  numOvLabels = 16, numOvExLabels = 16;
5158   char     *ovLabelNames[16], *ovExLabelNames[16];
5159   PetscInt  numOvValues = 16, numOvExValues = 16, l;
5160   PetscBool flg;
5161 
5162   PetscFunctionBegin;
5163   PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0));
5164   PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg));
5165   if (!flg) numOvLabels = 0;
5166   if (numOvLabels) {
5167     ((DM_Plex *)dm->data)->numOvLabels = numOvLabels;
5168     for (l = 0; l < numOvLabels; ++l) {
5169       PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l]));
5170       PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]);
5171       PetscCall(PetscFree(ovLabelNames[l]));
5172     }
5173     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg));
5174     if (!flg) numOvValues = 0;
5175     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);
5176 
5177     PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg));
5178     if (!flg) numOvExLabels = 0;
5179     ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels;
5180     for (l = 0; l < numOvExLabels; ++l) {
5181       PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l]));
5182       PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]);
5183       PetscCall(PetscFree(ovExLabelNames[l]));
5184     }
5185     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg));
5186     if (!flg) numOvExValues = 0;
5187     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);
5188   }
5189   PetscFunctionReturn(PETSC_SUCCESS);
5190 }
5191 
DMSetFromOptions_Plex(DM dm,PetscOptionItems PetscOptionsObject)5192 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems PetscOptionsObject)
5193 {
5194   PetscFunctionList    ordlist;
5195   char                 oname[256];
5196   char                 sublabelname[PETSC_MAX_PATH_LEN] = "";
5197   DMReorderDefaultFlag reorder;
5198   PetscReal            volume    = -1.0;
5199   PetscInt             prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim;
5200   PetscBool            uniformOrig = PETSC_FALSE, uniform = PETSC_TRUE, distribute, saveSF = PETSC_FALSE, interpolate = PETSC_TRUE, coordSpace = PETSC_FALSE, remap = PETSC_TRUE, ghostCells = PETSC_FALSE, isHierarchy, flg;
5201 
5202   PetscFunctionBegin;
5203   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options");
5204   if (dm->cloneOpts) goto non_refine;
5205   /* Handle automatic creation */
5206   PetscCall(DMGetDimension(dm, &dim));
5207   if (dim < 0) PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm));
5208   PetscCall(DMGetDimension(dm, &dim));
5209   /* Handle interpolation before distribution */
5210   PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg));
5211   if (flg) {
5212     DMPlexInterpolatedFlag interpolated;
5213 
5214     PetscCall(DMPlexIsInterpolated(dm, &interpolated));
5215     if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) {
5216       DM udm;
5217 
5218       PetscCall(DMPlexUninterpolate(dm, &udm));
5219       PetscCall(DMPlexReplace_Internal(dm, &udm));
5220     } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) {
5221       DM idm;
5222 
5223       PetscCall(DMPlexInterpolate(dm, &idm));
5224       PetscCall(DMPlexReplace_Internal(dm, &idm));
5225     }
5226   }
5227   // Handle submesh selection before distribution
5228   PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg));
5229   if (flg) {
5230     DM              subdm;
5231     DMLabel         label;
5232     IS              valueIS, pointIS;
5233     const PetscInt *values, *points;
5234     PetscBool       markedFaces = PETSC_FALSE;
5235     PetscInt        Nv, value, Np;
5236 
5237     PetscCall(DMGetLabel(dm, sublabelname, &label));
5238     PetscCall(DMLabelGetNumValues(label, &Nv));
5239     PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv);
5240     PetscCall(DMLabelGetValueIS(label, &valueIS));
5241     PetscCall(ISGetIndices(valueIS, &values));
5242     value = values[0];
5243     PetscCall(ISRestoreIndices(valueIS, &values));
5244     PetscCall(ISDestroy(&valueIS));
5245     PetscCall(DMLabelGetStratumSize(label, value, &Np));
5246     PetscCall(DMLabelGetStratumIS(label, value, &pointIS));
5247     PetscCall(ISGetIndices(pointIS, &points));
5248     for (PetscInt p = 0; p < Np; ++p) {
5249       PetscInt pdepth;
5250 
5251       PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth));
5252       if (pdepth) {
5253         markedFaces = PETSC_TRUE;
5254         break;
5255       }
5256     }
5257     PetscCall(ISRestoreIndices(pointIS, &points));
5258     PetscCall(ISDestroy(&pointIS));
5259     PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm));
5260     PetscCall(DMPlexReplace_Internal(dm, &subdm));
5261     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5262   }
5263   /* Handle DMPlex refinement before distribution */
5264   PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig));
5265   PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0));
5266   PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
5267   PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg));
5268   if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform));
5269   PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg));
5270   if (flg) {
5271     PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE));
5272     PetscCall(DMPlexSetRefinementLimit(dm, volume));
5273     prerefine = PetscMax(prerefine, 1);
5274   }
5275   if (prerefine) PetscCall(DMLocalizeCoordinates(dm));
5276   for (r = 0; r < prerefine; ++r) {
5277     DM            rdm;
5278     PetscPointFn *coordFunc;
5279 
5280     PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
5281     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5282     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
5283     PetscCall(DMPlexReplace_Internal(dm, &rdm));
5284     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5285     if (coordFunc && remap) {
5286       PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
5287       PetscCall(DMPlexSetCoordinateMap(dm, coordFunc));
5288     }
5289   }
5290   PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig));
5291   /* Handle DMPlex extrusion before distribution */
5292   PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0));
5293   if (extLayers) {
5294     DM edm;
5295 
5296     PetscCall(DMExtrude(dm, extLayers, &edm));
5297     PetscCall(DMPlexReplace_Internal(dm, &edm));
5298     PetscCall(DMPlexSetCoordinateMap(dm, NULL));
5299     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5300     extLayers = 0;
5301     PetscCall(DMGetDimension(dm, &dim));
5302   }
5303   /* Handle DMPlex reordering before distribution */
5304   PetscCall(DMPlexReorderGetDefault(dm, &reorder));
5305   PetscCall(MatGetOrderingList(&ordlist));
5306   PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname)));
5307   PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg));
5308   if (reorder == DM_REORDER_DEFAULT_TRUE || flg) {
5309     DM pdm;
5310     IS perm;
5311 
5312     PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm));
5313     PetscCall(DMPlexPermute(dm, perm, &pdm));
5314     PetscCall(ISDestroy(&perm));
5315     PetscCall(DMPlexReplace_Internal(dm, &pdm));
5316     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5317   }
5318   /* Handle DMPlex distribution */
5319   PetscCall(DMPlexDistributeGetDefault(dm, &distribute));
5320   PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL));
5321   PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL));
5322   PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
5323   if (distribute) {
5324     DM               pdm = NULL;
5325     PetscPartitioner part;
5326     PetscSF          sfMigration;
5327     PetscBool        use_partition_balance;
5328 
5329     PetscCall(DMPlexGetPartitioner(dm, &part));
5330     PetscCall(PetscPartitionerSetFromOptions(part));
5331     PetscCall(DMPlexGetPartitionBalance(dm, &use_partition_balance));
5332     PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", use_partition_balance, &use_partition_balance, &flg));
5333     if (flg) PetscCall(DMPlexSetPartitionBalance(dm, use_partition_balance));
5334     PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm));
5335     if (pdm) {
5336       // Delete the local section to force the existing one to be rebuilt with the distributed DM
5337       PetscCall(DMSetLocalSection(dm, pdm->localSection));
5338       PetscCall(DMPlexReplace_Internal(dm, &pdm));
5339     }
5340     if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration));
5341     PetscCall(PetscSFDestroy(&sfMigration));
5342   }
5343 
5344   {
5345     PetscBool useBoxLabel = PETSC_FALSE;
5346     PetscCall(PetscOptionsBool("-dm_plex_box_label", "Create 'Face Sets' assuming boundary faces align with cartesian directions", "DMCreate", useBoxLabel, &useBoxLabel, NULL));
5347     if (useBoxLabel) {
5348       PetscInt       n      = 3;
5349       DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
5350 
5351       PetscCall(PetscOptionsEnumArray("-dm_plex_box_label_bd", "Boundary type for each dimension when using -dm_plex_box_label", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
5352       PetscCheck(!flg || !(n != dim), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
5353       PetscCall(DMPlexSetBoxLabel_Internal(dm, bdt));
5354     }
5355   }
5356   /* Must check CEED options before creating function space for coordinates */
5357   {
5358     PetscBool useCeed = PETSC_FALSE, flg;
5359 
5360     PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg));
5361     if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed));
5362   }
5363   /* Create coordinate space */
5364   PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, NULL));
5365   if (coordSpace) {
5366     PetscInt  degree = 1, deg;
5367     PetscInt  height = 0;
5368     DM        cdm;
5369     PetscBool localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE;
5370 
5371     PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, &degree, NULL));
5372     PetscCall(DMGetCoordinateDegree_Internal(dm, &deg));
5373     if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_FALSE, PETSC_TRUE));
5374     PetscCall(DMGetCoordinateDM(dm, &cdm));
5375     if (!coordSpace) {
5376       PetscDS      cds;
5377       PetscObject  obj;
5378       PetscClassId id;
5379 
5380       PetscCall(DMGetDS(cdm, &cds));
5381       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
5382       PetscCall(PetscObjectGetClassId(obj, &id));
5383       if (id == PETSCFE_CLASSID) {
5384         PetscContainer unused;
5385 
5386         PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &unused));
5387         PetscCall(PetscObjectSetName((PetscObject)unused, "coordinates"));
5388         PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)unused));
5389         PetscCall(PetscContainerDestroy(&unused));
5390         PetscCall(DMClearDS(cdm));
5391       }
5392       PetscCall(DMPlexSetCoordinateMap(dm, NULL));
5393     }
5394     PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL));
5395     PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg));
5396     if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize));
5397     PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg));
5398     if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height));
5399     if (localize) PetscCall(DMLocalizeCoordinates(dm));
5400   }
5401   /* Handle DMPlex refinement */
5402   remap = PETSC_TRUE;
5403   PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0));
5404   PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
5405   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0));
5406   if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
5407   if (refine && isHierarchy) {
5408     DM *dms, coarseDM;
5409 
5410     PetscCall(DMGetCoarseDM(dm, &coarseDM));
5411     PetscCall(PetscObjectReference((PetscObject)coarseDM));
5412     PetscCall(PetscMalloc1(refine, &dms));
5413     PetscCall(DMRefineHierarchy(dm, refine, dms));
5414     /* Total hack since we do not pass in a pointer */
5415     PetscCall(DMPlexSwap_Static(dm, dms[refine - 1]));
5416     if (refine == 1) {
5417       PetscCall(DMSetCoarseDM(dm, dms[0]));
5418       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
5419     } else {
5420       PetscCall(DMSetCoarseDM(dm, dms[refine - 2]));
5421       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
5422       PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1]));
5423       PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE));
5424     }
5425     PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM));
5426     PetscCall(PetscObjectDereference((PetscObject)coarseDM));
5427     /* Free DMs */
5428     for (r = 0; r < refine; ++r) {
5429       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
5430       PetscCall(DMDestroy(&dms[r]));
5431     }
5432     PetscCall(PetscFree(dms));
5433   } else {
5434     for (r = 0; r < refine; ++r) {
5435       DM            rdm;
5436       PetscPointFn *coordFunc;
5437 
5438       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5439       PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
5440       /* Total hack since we do not pass in a pointer */
5441       PetscCall(DMPlexReplace_Internal(dm, &rdm));
5442       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5443       PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
5444       if (coordFunc && remap) {
5445         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
5446         PetscCall(DMPlexSetCoordinateMap(dm, coordFunc));
5447       }
5448     }
5449   }
5450   /* Handle DMPlex coarsening */
5451   PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0));
5452   PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0));
5453   if (coarsen && isHierarchy) {
5454     DM *dms;
5455 
5456     PetscCall(PetscMalloc1(coarsen, &dms));
5457     PetscCall(DMCoarsenHierarchy(dm, coarsen, dms));
5458     /* Free DMs */
5459     for (r = 0; r < coarsen; ++r) {
5460       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
5461       PetscCall(DMDestroy(&dms[r]));
5462     }
5463     PetscCall(PetscFree(dms));
5464   } else {
5465     for (r = 0; r < coarsen; ++r) {
5466       DM            cdm;
5467       PetscPointFn *coordFunc;
5468 
5469       PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
5470       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5471       PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm));
5472       /* Total hack since we do not pass in a pointer */
5473       PetscCall(DMPlexReplace_Internal(dm, &cdm));
5474       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5475       if (coordFunc) {
5476         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
5477         PetscCall(DMPlexSetCoordinateMap(dm, coordFunc));
5478       }
5479     }
5480   }
5481   // Handle coordinate remapping
5482   remap = PETSC_FALSE;
5483   PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL));
5484   if (remap) {
5485     DMPlexCoordMap map     = DM_COORD_MAP_NONE;
5486     PetscPointFn  *mapFunc = NULL;
5487     PetscScalar    params[16];
5488     PetscInt       Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim;
5489     MPI_Comm       comm;
5490 
5491     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5492     PetscCall(DMGetCoordinateDim(dm, &cdim));
5493     PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg));
5494     if (!flg) Np = 0;
5495     // TODO Allow user to pass a map function by name
5496     PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg));
5497     if (flg) {
5498       switch (map) {
5499       case DM_COORD_MAP_NONE:
5500         mapFunc = coordMap_identity;
5501         break;
5502       case DM_COORD_MAP_SHEAR:
5503         mapFunc = coordMap_shear;
5504         if (!Np) {
5505           Np        = cdim + 1;
5506           params[0] = 0;
5507           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
5508         }
5509         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);
5510         break;
5511       case DM_COORD_MAP_FLARE:
5512         mapFunc = coordMap_flare;
5513         if (!Np) {
5514           Np        = cdim + 1;
5515           params[0] = 0;
5516           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
5517         }
5518         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);
5519         break;
5520       case DM_COORD_MAP_ANNULUS:
5521         mapFunc = coordMap_annulus;
5522         if (!Np) {
5523           Np        = 2;
5524           params[0] = 1.;
5525           params[1] = 2.;
5526         }
5527         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
5528         break;
5529       case DM_COORD_MAP_SHELL:
5530         mapFunc = coordMap_shell;
5531         if (!Np) {
5532           Np        = 2;
5533           params[0] = 1.;
5534           params[1] = 2.;
5535         }
5536         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
5537         break;
5538       case DM_COORD_MAP_SINUSOID:
5539         mapFunc = coordMap_sinusoid;
5540         if (!Np) {
5541           Np        = 3;
5542           params[0] = 1.;
5543           params[1] = 1.;
5544           params[2] = 1.;
5545         }
5546         PetscCheck(Np == 3, comm, PETSC_ERR_ARG_WRONG, "The sinusoidal coordinate map must have 3 parameters, not %" PetscInt_FMT, Np);
5547         break;
5548       default:
5549         mapFunc = coordMap_identity;
5550       }
5551     }
5552     if (Np) {
5553       DM      cdm;
5554       PetscDS cds;
5555 
5556       PetscCall(DMGetCoordinateDM(dm, &cdm));
5557       PetscCall(DMGetDS(cdm, &cds));
5558       PetscCall(PetscDSSetConstants(cds, Np, params));
5559     }
5560     PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc));
5561   }
5562   /* Handle ghost cells */
5563   PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL));
5564   if (ghostCells) {
5565     DM   gdm;
5566     char lname[PETSC_MAX_PATH_LEN];
5567 
5568     lname[0] = '\0';
5569     PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg));
5570     PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm));
5571     PetscCall(DMPlexReplace_Internal(dm, &gdm));
5572   }
5573   /* Handle 1D order */
5574   if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) {
5575     DM           cdm, rdm;
5576     PetscDS      cds;
5577     PetscObject  obj;
5578     PetscClassId id = PETSC_OBJECT_CLASSID;
5579     IS           perm;
5580     PetscInt     Nf;
5581     PetscBool    distributed;
5582 
5583     PetscCall(DMPlexIsDistributed(dm, &distributed));
5584     PetscCall(DMGetCoordinateDM(dm, &cdm));
5585     PetscCall(DMGetDS(cdm, &cds));
5586     PetscCall(PetscDSGetNumFields(cds, &Nf));
5587     if (Nf) {
5588       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
5589       PetscCall(PetscObjectGetClassId(obj, &id));
5590     }
5591     if (!distributed && id != PETSCFE_CLASSID) {
5592       PetscCall(DMPlexGetOrdering1D(dm, &perm));
5593       PetscCall(DMPlexPermute(dm, perm, &rdm));
5594       PetscCall(DMPlexReplace_Internal(dm, &rdm));
5595       PetscCall(ISDestroy(&perm));
5596     }
5597   }
5598 /* Handle */
5599 non_refine:
5600   PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5601   char    *phases[16];
5602   PetscInt Nphases = 16;
5603   PetscCall(PetscOptionsStringArray("-dm_plex_option_phases", "Option phase prefixes", "DMSetFromOptions", phases, &Nphases, &flg));
5604   PetscOptionsHeadEnd();
5605 
5606   // Phases
5607   if (flg) {
5608     DM          cdm;
5609     char       *oldPrefix, *oldCoordPrefix;
5610     const char *tmp;
5611 
5612     PetscCall(DMGetCoordinateDM(dm, &cdm));
5613     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &tmp));
5614     PetscCall(PetscStrallocpy(tmp, &oldPrefix));
5615     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)cdm, &tmp));
5616     PetscCall(PetscStrallocpy(tmp, &oldCoordPrefix));
5617     for (PetscInt ph = 0; ph < Nphases; ++ph) {
5618       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, phases[ph]));
5619       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)cdm, phases[ph]));
5620       PetscCall(PetscInfo(dm, "Options phase %s for DM %s\n", phases[ph], dm->hdr.name));
5621       PetscCall(DMSetFromOptions(dm));
5622       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix));
5623       PetscCall(DMGetCoordinateDM(dm, &cdm));
5624       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)cdm, oldCoordPrefix));
5625       PetscCall(PetscFree(phases[ph]));
5626     }
5627     PetscCall(PetscFree(oldPrefix));
5628     PetscCall(PetscFree(oldCoordPrefix));
5629   }
5630   PetscFunctionReturn(PETSC_SUCCESS);
5631 }
5632 
DMCreateGlobalVector_Plex(DM dm,Vec * vec)5633 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec)
5634 {
5635   PetscFunctionBegin;
5636   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
5637   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
5638   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Plex));
5639   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (PetscErrorCodeFn *)VecView_Plex_Native));
5640   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (PetscErrorCodeFn *)VecLoad_Plex));
5641   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (PetscErrorCodeFn *)VecLoad_Plex_Native));
5642   PetscFunctionReturn(PETSC_SUCCESS);
5643 }
5644 
DMCreateLocalVector_Plex(DM dm,Vec * vec)5645 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec)
5646 {
5647   PetscFunctionBegin;
5648   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
5649   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Plex_Local));
5650   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (PetscErrorCodeFn *)VecLoad_Plex_Local));
5651   PetscFunctionReturn(PETSC_SUCCESS);
5652 }
5653 
DMGetDimPoints_Plex(DM dm,PetscInt dim,PetscInt * pStart,PetscInt * pEnd)5654 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5655 {
5656   PetscInt depth, d;
5657 
5658   PetscFunctionBegin;
5659   PetscCall(DMPlexGetDepth(dm, &depth));
5660   if (depth == 1) {
5661     PetscCall(DMGetDimension(dm, &d));
5662     if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
5663     else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd));
5664     else {
5665       *pStart = 0;
5666       *pEnd   = 0;
5667     }
5668   } else {
5669     PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
5670   }
5671   PetscFunctionReturn(PETSC_SUCCESS);
5672 }
5673 
DMGetNeighbors_Plex(DM dm,PetscInt * nranks,const PetscMPIInt * ranks[])5674 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
5675 {
5676   PetscSF            sf;
5677   PetscMPIInt        niranks, njranks;
5678   PetscInt           n;
5679   const PetscMPIInt *iranks, *jranks;
5680   DM_Plex           *data = (DM_Plex *)dm->data;
5681 
5682   PetscFunctionBegin;
5683   PetscCall(DMGetPointSF(dm, &sf));
5684   if (!data->neighbors) {
5685     PetscCall(PetscSFSetUp(sf));
5686     PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL));
5687     PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL));
5688     PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors));
5689     PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks));
5690     PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks));
5691     n = njranks + niranks;
5692     PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1));
5693     /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */
5694     PetscCall(PetscMPIIntCast(n, data->neighbors));
5695   }
5696   if (nranks) *nranks = data->neighbors[0];
5697   if (ranks) {
5698     if (data->neighbors[0]) *ranks = data->neighbors + 1;
5699     else *ranks = NULL;
5700   }
5701   PetscFunctionReturn(PETSC_SUCCESS);
5702 }
5703 
5704 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec);
5705 
DMInitialize_Plex(DM dm)5706 static PetscErrorCode DMInitialize_Plex(DM dm)
5707 {
5708   PetscFunctionBegin;
5709   dm->ops->view                      = DMView_Plex;
5710   dm->ops->load                      = DMLoad_Plex;
5711   dm->ops->setfromoptions            = DMSetFromOptions_Plex;
5712   dm->ops->clone                     = DMClone_Plex;
5713   dm->ops->setup                     = DMSetUp_Plex;
5714   dm->ops->createlocalsection        = DMCreateLocalSection_Plex;
5715   dm->ops->createsectionpermutation  = DMCreateSectionPermutation_Plex;
5716   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_Plex;
5717   dm->ops->createglobalvector        = DMCreateGlobalVector_Plex;
5718   dm->ops->createlocalvector         = DMCreateLocalVector_Plex;
5719   dm->ops->getlocaltoglobalmapping   = NULL;
5720   dm->ops->createfieldis             = NULL;
5721   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_Plex;
5722   dm->ops->createcellcoordinatedm    = DMCreateCellCoordinateDM_Plex;
5723   dm->ops->createcoordinatefield     = DMCreateCoordinateField_Plex;
5724   dm->ops->getcoloring               = NULL;
5725   dm->ops->creatematrix              = DMCreateMatrix_Plex;
5726   dm->ops->createinterpolation       = DMCreateInterpolation_Plex;
5727   dm->ops->createmassmatrix          = DMCreateMassMatrix_Plex;
5728   dm->ops->createmassmatrixlumped    = DMCreateMassMatrixLumped_Plex;
5729   dm->ops->creategradientmatrix      = DMCreateGradientMatrix_Plex;
5730   dm->ops->createinjection           = DMCreateInjection_Plex;
5731   dm->ops->refine                    = DMRefine_Plex;
5732   dm->ops->coarsen                   = DMCoarsen_Plex;
5733   dm->ops->refinehierarchy           = DMRefineHierarchy_Plex;
5734   dm->ops->coarsenhierarchy          = DMCoarsenHierarchy_Plex;
5735   dm->ops->extrude                   = DMExtrude_Plex;
5736   dm->ops->globaltolocalbegin        = NULL;
5737   dm->ops->globaltolocalend          = NULL;
5738   dm->ops->localtoglobalbegin        = NULL;
5739   dm->ops->localtoglobalend          = NULL;
5740   dm->ops->destroy                   = DMDestroy_Plex;
5741   dm->ops->createsubdm               = DMCreateSubDM_Plex;
5742   dm->ops->createsuperdm             = DMCreateSuperDM_Plex;
5743   dm->ops->getdimpoints              = DMGetDimPoints_Plex;
5744   dm->ops->locatepoints              = DMLocatePoints_Plex;
5745   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_Plex;
5746   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex;
5747   dm->ops->projectfieldlocal         = DMProjectFieldLocal_Plex;
5748   dm->ops->projectfieldlabellocal    = DMProjectFieldLabelLocal_Plex;
5749   dm->ops->projectbdfieldlabellocal  = DMProjectBdFieldLabelLocal_Plex;
5750   dm->ops->computel2diff             = DMComputeL2Diff_Plex;
5751   dm->ops->computel2gradientdiff     = DMComputeL2GradientDiff_Plex;
5752   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_Plex;
5753   dm->ops->getneighbors              = DMGetNeighbors_Plex;
5754   dm->ops->getlocalboundingbox       = DMGetLocalBoundingBox_Coordinates;
5755   dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex;
5756   dm->ops->createddscatters          = DMCreateDomainDecompositionScatters_Plex;
5757   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex));
5758   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex));
5759   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", DMPlexInsertBounds_Plex));
5760   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex));
5761   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex));
5762   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex));
5763   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex));
5764   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex));
5765   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex));
5766   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex));
5767   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex));
5768   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex));
5769   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex));
5770   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex));
5771   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex));
5772   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex));
5773   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex));
5774   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex));
5775   PetscFunctionReturn(PETSC_SUCCESS);
5776 }
5777 
DMClone_Plex(DM dm,DM * newdm)5778 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
5779 {
5780   DM_Plex       *mesh = (DM_Plex *)dm->data;
5781   const PetscSF *face_sfs;
5782   PetscInt       num_face_sfs;
5783 
5784   PetscFunctionBegin;
5785   mesh->refct++;
5786   (*newdm)->data = mesh;
5787   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs));
5788   PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs));
5789   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX));
5790   PetscCall(DMInitialize_Plex(*newdm));
5791   PetscFunctionReturn(PETSC_SUCCESS);
5792 }
5793 
5794 /*MC
5795   DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh (or grid), or CW Complex {cite}`cwcomplex`,
5796            which can be expressed using a Hasse Diagram {cite}`hassediagram`.
5797            In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is
5798            specified by a `PetscSection` object. Ownership in the global representation is determined by
5799            ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object.
5800 
5801   Options Database Keys:
5802 + -dm_refine_pre                     - Refine mesh before distribution
5803 + -dm_refine_uniform_pre             - Choose uniform or generator-based refinement
5804 + -dm_refine_volume_limit_pre        - Cell volume limit after pre-refinement using generator
5805 . -dm_distribute                     - Distribute mesh across processes
5806 . -dm_distribute_overlap             - Number of cells to overlap for distribution
5807 . -dm_refine                         - Refine mesh after distribution
5808 . -dm_localize <bool>                - Whether to localize coordinates for periodic meshes
5809 . -dm_sparse_localize <bool>         - Whether to only localize cells on the periodic boundary
5810 . -dm_plex_hash_location             - Use grid hashing for point location
5811 . -dm_plex_hash_box_faces <n,m,p>    - The number of divisions in each direction of the grid hash
5812 . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
5813 . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
5814 . -dm_plex_max_projection_height     - Maximum mesh point height used to project locally
5815 . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
5816 . -dm_plex_reorder_section           - Use specialized blocking if available
5817 . -dm_plex_check_all                 - Perform all checks below
5818 . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
5819 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
5820 . -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
5821 . -dm_plex_check_geometry            - Check that cells have positive volume
5822 . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
5823 . -dm_plex_view_scale <num>          - Scale the TikZ
5824 . -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices
5825 - -dm_plex_print_fvm <num>           - View FVM assembly information, such as flux updates
5826 
5827   Level: intermediate
5828 
5829 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection`
5830 M*/
5831 
DMCreate_Plex(DM dm)5832 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
5833 {
5834   DM_Plex *mesh;
5835   PetscInt unit;
5836 
5837   PetscFunctionBegin;
5838   PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite));
5839   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5840   PetscCall(PetscNew(&mesh));
5841   dm->reorderSection = DM_REORDER_DEFAULT_NOTSET;
5842   dm->data           = mesh;
5843 
5844   mesh->refct = 1;
5845   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection));
5846   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection));
5847   mesh->refinementUniform       = PETSC_TRUE;
5848   mesh->refinementLimit         = -1.0;
5849   mesh->distDefault             = PETSC_TRUE;
5850   mesh->reorderDefault          = DM_REORDER_DEFAULT_NOTSET;
5851   mesh->distributionName        = NULL;
5852   mesh->interpolated            = DMPLEX_INTERPOLATED_INVALID;
5853   mesh->interpolatedCollective  = DMPLEX_INTERPOLATED_INVALID;
5854   mesh->interpolatePreferTensor = PETSC_TRUE;
5855 
5856   PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner));
5857   mesh->remeshBd = PETSC_FALSE;
5858 
5859   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;
5860 
5861   mesh->depthState    = -1;
5862   mesh->celltypeState = -1;
5863   mesh->printTol      = 1.0e-10;
5864   mesh->nonempty_comm = MPI_COMM_SELF;
5865 
5866   PetscCall(DMInitialize_Plex(dm));
5867   PetscFunctionReturn(PETSC_SUCCESS);
5868 }
5869 
5870 /*@
5871   DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.
5872 
5873   Collective
5874 
5875   Input Parameter:
5876 . comm - The communicator for the `DMPLEX` object
5877 
5878   Output Parameter:
5879 . mesh - The `DMPLEX` object
5880 
5881   Level: beginner
5882 
5883 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()`
5884 @*/
DMPlexCreate(MPI_Comm comm,DM * mesh)5885 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
5886 {
5887   PetscFunctionBegin;
5888   PetscAssertPointer(mesh, 2);
5889   PetscCall(DMCreate(comm, mesh));
5890   PetscCall(DMSetType(*mesh, DMPLEX));
5891   PetscFunctionReturn(PETSC_SUCCESS);
5892 }
5893 
5894 /*@C
5895   DMPlexBuildFromCellListParallel - Build a distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype
5896 
5897   Collective; No Fortran Support
5898 
5899   Input Parameters:
5900 + dm          - The `DM`
5901 . numCells    - The number of cells owned by this process
5902 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
5903 . NVertices   - The global number of vertices, or `PETSC_DETERMINE`
5904 . numCorners  - The number of vertices for each cell
5905 - cells       - An array of $ numCells \times numCorners$ numbers, the global vertex numbers for each cell
5906 
5907   Output Parameters:
5908 + vertexSF         - (Optional) `PetscSF` describing complete vertex ownership
5909 - verticesAdjSaved - (Optional) vertex adjacency array, must be freed by user
5910 
5911   Level: advanced
5912 
5913   Notes:
5914   Two triangles sharing a face
5915 .vb
5916 
5917         2
5918       / | \
5919      /  |  \
5920     /   |   \
5921    0  0 | 1  3
5922     \   |   /
5923      \  |  /
5924       \ | /
5925         1
5926 .ve
5927   would have input
5928 .vb
5929   numCells = 2, numVertices = 4
5930   cells = [0 1 2  1 3 2]
5931 .ve
5932   which would result in the `DMPLEX`
5933 .vb
5934 
5935         4
5936       / | \
5937      /  |  \
5938     /   |   \
5939    2  0 | 1  5
5940     \   |   /
5941      \  |  /
5942       \ | /
5943         3
5944 .ve
5945 
5946   Vertices are implicitly numbered consecutively $0, \ldots, \mathrm{NVertices}$.
5947 
5948   Each process owns a chunk of `numVertices` consecutive vertices.
5949 
5950   If `numVertices` is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using `PetscLayout`.
5951 
5952   If `NVertices` is `PETSC_DETERMINE` and `numVertices` is `PETSC_DECIDE`, `NVertices` is computed by PETSc as the maximum vertex index in $ cells + 1 $.
5953 
5954   If only `NVertices` is `PETSC_DETERMINE`, it is computed as the sum of `numVertices` over all processes.
5955 
5956   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.
5957 
5958 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
5959           `PetscSF`
5960 @*/
DMPlexBuildFromCellListParallel(DM dm,PetscInt numCells,PetscInt numVertices,PetscInt NVertices,PetscInt numCorners,const PetscInt cells[],PeOp PetscSF * vertexSF,PeOp PetscInt * verticesAdjSaved[])5961 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[])
5962 {
5963   PetscSF     sfPoint;
5964   PetscLayout layout;
5965   PetscInt    numVerticesAdj, *verticesAdj, *cones, c, p;
5966 
5967   PetscFunctionBegin;
5968   PetscValidLogicalCollectiveInt(dm, NVertices, 4);
5969   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5970   /* Get/check global number of vertices */
5971   {
5972     PetscInt       NVerticesInCells, i;
5973     const PetscInt len = numCells * numCorners;
5974 
5975     /* NVerticesInCells = max(cells) + 1 */
5976     NVerticesInCells = PETSC_INT_MIN;
5977     for (i = 0; i < len; i++)
5978       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
5979     ++NVerticesInCells;
5980     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
5981 
5982     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
5983     else
5984       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);
5985   }
5986   /* Count locally unique vertices */
5987   {
5988     PetscHSetI vhash;
5989     PetscInt   off = 0;
5990 
5991     PetscCall(PetscHSetICreate(&vhash));
5992     for (c = 0; c < numCells; ++c) {
5993       for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p]));
5994     }
5995     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
5996     PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
5997     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
5998     PetscCall(PetscHSetIDestroy(&vhash));
5999     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
6000   }
6001   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
6002   /* Create cones */
6003   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
6004   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
6005   PetscCall(DMSetUp(dm));
6006   PetscCall(DMPlexGetCones(dm, &cones));
6007   for (c = 0; c < numCells; ++c) {
6008     for (p = 0; p < numCorners; ++p) {
6009       const PetscInt gv = cells[c * numCorners + p];
6010       PetscInt       lv;
6011 
6012       /* Positions within verticesAdj form 0-based local vertex numbering;
6013          we need to shift it by numCells to get correct DAG points (cells go first) */
6014       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
6015       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
6016       cones[c * numCorners + p] = lv + numCells;
6017     }
6018   }
6019   /* Build point sf */
6020   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
6021   PetscCall(PetscLayoutSetSize(layout, NVertices));
6022   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
6023   PetscCall(PetscLayoutSetBlockSize(layout, 1));
6024   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
6025   PetscCall(PetscLayoutDestroy(&layout));
6026   if (verticesAdjSaved) *verticesAdjSaved = verticesAdj;
6027   else PetscCall(PetscFree(verticesAdj));
6028   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
6029   if (dm->sf) {
6030     const char *prefix;
6031 
6032     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
6033     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
6034   }
6035   PetscCall(DMSetPointSF(dm, sfPoint));
6036   PetscCall(PetscSFDestroy(&sfPoint));
6037   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF"));
6038   /* Fill in the rest of the topology structure */
6039   PetscCall(DMPlexSymmetrize(dm));
6040   PetscCall(DMPlexStratify(dm));
6041   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6042   PetscFunctionReturn(PETSC_SUCCESS);
6043 }
6044 
6045 /*@C
6046   DMPlexBuildFromCellSectionParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) allowing multiple celltypes
6047 
6048   Collective; No Fortran Support
6049 
6050   Input Parameters:
6051 + dm          - The `DM`
6052 . numCells    - The number of cells owned by this process
6053 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
6054 . NVertices   - The global number of vertices, or `PETSC_DETERMINE`
6055 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells)
6056 - cells       - An array of the global vertex numbers for each cell
6057 
6058   Output Parameters:
6059 + vertexSF         - (Optional) `PetscSF` describing complete vertex ownership
6060 - verticesAdjSaved - (Optional) vertex adjacency array, must be freed by user
6061 
6062   Level: advanced
6063 
6064   Notes:
6065   A triangle and quadrilateral sharing a face
6066 .vb
6067         2----------3
6068       / |          |
6069      /  |          |
6070     /   |          |
6071    0  0 |     1    |
6072     \   |          |
6073      \  |          |
6074       \ |          |
6075         1----------4
6076 .ve
6077   would have input
6078 .vb
6079   numCells = 2, numVertices = 5
6080   cells = [0 1 2  1 4 3 2]
6081 .ve
6082   which would result in the `DMPLEX`
6083 .vb
6084         4----------5
6085       / |          |
6086      /  |          |
6087     /   |          |
6088    2  0 |     1    |
6089     \   |          |
6090      \  |          |
6091       \ |          |
6092         3----------6
6093 .ve
6094 
6095   Vertices are implicitly numbered consecutively 0,...,NVertices.
6096   Each rank owns a chunk of numVertices consecutive vertices.
6097   If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout.
6098   If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1.
6099   If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks.
6100 
6101   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.
6102 
6103 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexCreateFromCellSectionParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
6104           `PetscSF`
6105 @*/
DMPlexBuildFromCellSectionParallel(DM dm,PetscInt numCells,PetscInt numVertices,PetscInt NVertices,PetscSection cellSection,const PetscInt cells[],PeOp PetscSF * vertexSF,PeOp PetscInt * verticesAdjSaved[])6106 PetscErrorCode DMPlexBuildFromCellSectionParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[])
6107 {
6108   PetscSF     sfPoint;
6109   PetscLayout layout;
6110   PetscInt    numVerticesAdj, *verticesAdj, *cones, cStart, cEnd, len;
6111 
6112   PetscFunctionBegin;
6113   PetscValidLogicalCollectiveInt(dm, NVertices, 4);
6114   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6115   PetscCall(PetscSectionGetChart(cellSection, &cStart, &cEnd));
6116   PetscCall(PetscSectionGetStorageSize(cellSection, &len));
6117   PetscCheck(cStart == 0 && cEnd == numCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section chart [%" PetscInt_FMT ", %" PetscInt_FMT ") should be [0, %" PetscInt_FMT ")", cStart, cEnd, numCells);
6118   /* Get/check global number of vertices */
6119   {
6120     PetscInt NVerticesInCells;
6121 
6122     /* NVerticesInCells = max(cells) + 1 */
6123     NVerticesInCells = PETSC_MIN_INT;
6124     for (PetscInt i = 0; i < len; i++)
6125       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
6126     ++NVerticesInCells;
6127     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
6128 
6129     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
6130     else
6131       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);
6132   }
6133   /* Count locally unique vertices */
6134   {
6135     PetscHSetI vhash;
6136     PetscInt   off = 0;
6137 
6138     PetscCall(PetscHSetICreate(&vhash));
6139     for (PetscInt i = 0; i < len; i++) PetscCall(PetscHSetIAdd(vhash, cells[i]));
6140     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
6141     PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
6142     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
6143     PetscCall(PetscHSetIDestroy(&vhash));
6144     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
6145   }
6146   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
6147   /* Create cones */
6148   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
6149   for (PetscInt c = 0; c < numCells; ++c) {
6150     PetscInt dof;
6151 
6152     PetscCall(PetscSectionGetDof(cellSection, c, &dof));
6153     PetscCall(DMPlexSetConeSize(dm, c, dof));
6154   }
6155   PetscCall(DMSetUp(dm));
6156   PetscCall(DMPlexGetCones(dm, &cones));
6157   for (PetscInt c = 0; c < numCells; ++c) {
6158     PetscInt dof, off;
6159 
6160     PetscCall(PetscSectionGetDof(cellSection, c, &dof));
6161     PetscCall(PetscSectionGetOffset(cellSection, c, &off));
6162     for (PetscInt p = off; p < off + dof; ++p) {
6163       const PetscInt gv = cells[p];
6164       PetscInt       lv;
6165 
6166       /* Positions within verticesAdj form 0-based local vertex numbering;
6167          we need to shift it by numCells to get correct DAG points (cells go first) */
6168       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
6169       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
6170       cones[p] = lv + numCells;
6171     }
6172   }
6173   /* Build point sf */
6174   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
6175   PetscCall(PetscLayoutSetSize(layout, NVertices));
6176   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
6177   PetscCall(PetscLayoutSetBlockSize(layout, 1));
6178   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
6179   PetscCall(PetscLayoutDestroy(&layout));
6180   if (verticesAdjSaved) *verticesAdjSaved = verticesAdj;
6181   else PetscCall(PetscFree(verticesAdj));
6182   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
6183   if (dm->sf) {
6184     const char *prefix;
6185 
6186     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
6187     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
6188   }
6189   PetscCall(DMSetPointSF(dm, sfPoint));
6190   PetscCall(PetscSFDestroy(&sfPoint));
6191   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF"));
6192   /* Fill in the rest of the topology structure */
6193   PetscCall(DMPlexSymmetrize(dm));
6194   PetscCall(DMPlexStratify(dm));
6195   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6196   PetscFunctionReturn(PETSC_SUCCESS);
6197 }
6198 
6199 /*@
6200   DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)
6201 
6202   Collective; No Fortran Support
6203 
6204   Input Parameters:
6205 + dm           - The `DM`
6206 . spaceDim     - The spatial dimension used for coordinates
6207 . sfVert       - `PetscSF` describing complete vertex ownership
6208 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6209 
6210   Level: advanced
6211 
6212 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()`
6213 @*/
DMPlexBuildCoordinatesFromCellListParallel(DM dm,PetscInt spaceDim,PetscSF sfVert,const PetscReal vertexCoords[])6214 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[])
6215 {
6216   PetscSection coordSection;
6217   Vec          coordinates;
6218   PetscScalar *coords;
6219   PetscInt     numVertices, numVerticesAdj, coordSize, v, vStart, vEnd;
6220   PetscMPIInt  spaceDimi;
6221 
6222   PetscFunctionBegin;
6223   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
6224   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
6225   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
6226   PetscCall(DMSetCoordinateDim(dm, spaceDim));
6227   PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL));
6228   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);
6229   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6230   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6231   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
6232   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
6233   for (v = vStart; v < vEnd; ++v) {
6234     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
6235     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
6236   }
6237   PetscCall(PetscSectionSetUp(coordSection));
6238   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
6239   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates));
6240   PetscCall(VecSetBlockSize(coordinates, spaceDim));
6241   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
6242   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
6243   PetscCall(VecSetType(coordinates, VECSTANDARD));
6244   PetscCall(VecGetArray(coordinates, &coords));
6245   {
6246     MPI_Datatype coordtype;
6247 
6248     /* Need a temp buffer for coords if we have complex/single */
6249     PetscCall(PetscMPIIntCast(spaceDim, &spaceDimi));
6250     PetscCallMPI(MPI_Type_contiguous(spaceDimi, MPIU_SCALAR, &coordtype));
6251     PetscCallMPI(MPI_Type_commit(&coordtype));
6252 #if defined(PETSC_USE_COMPLEX)
6253     {
6254       PetscScalar *svertexCoords;
6255       PetscInt     i;
6256       PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords));
6257       for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i];
6258       PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
6259       PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
6260       PetscCall(PetscFree(svertexCoords));
6261     }
6262 #else
6263     PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
6264     PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
6265 #endif
6266     PetscCallMPI(MPI_Type_free(&coordtype));
6267   }
6268   PetscCall(VecRestoreArray(coordinates, &coords));
6269   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
6270   PetscCall(VecDestroy(&coordinates));
6271   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
6272   PetscFunctionReturn(PETSC_SUCCESS);
6273 }
6274 
6275 /*@
6276   DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype
6277 
6278   Collective
6279 
6280   Input Parameters:
6281 + comm         - The communicator
6282 . dim          - The topological dimension of the mesh
6283 . numCells     - The number of cells owned by this process
6284 . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`
6285 . NVertices    - The global number of vertices, or `PETSC_DECIDE`
6286 . numCorners   - The number of vertices for each cell
6287 . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
6288 . cells        - An array of numCells*numCorners numbers, the global vertex numbers for each cell
6289 . spaceDim     - The spatial dimension used for coordinates
6290 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6291 
6292   Output Parameters:
6293 + dm          - The `DM`
6294 . vertexSF    - (Optional) `PetscSF` describing complete vertex ownership
6295 - verticesAdj - (Optional) vertex adjacency array, must be freed by user
6296 
6297   Level: intermediate
6298 
6299   Notes:
6300   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
6301   `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`
6302 
6303   See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters.
6304 
6305   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.
6306 
6307 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
6308 @*/
DMPlexCreateFromCellListParallelPetsc(MPI_Comm comm,PetscInt dim,PetscInt numCells,PetscInt numVertices,PetscInt NVertices,PetscInt numCorners,PetscBool interpolate,const PetscInt cells[],PetscInt spaceDim,const PetscReal vertexCoords[],PeOp PetscSF * vertexSF,PeOp PetscInt * verticesAdj[],DM * dm)6309 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[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdj[], DM *dm)
6310 {
6311   PetscSF sfVert;
6312 
6313   PetscFunctionBegin;
6314   PetscCall(DMCreate(comm, dm));
6315   PetscCall(DMSetType(*dm, DMPLEX));
6316   PetscValidLogicalCollectiveInt(*dm, dim, 2);
6317   PetscValidLogicalCollectiveInt(*dm, spaceDim, 9);
6318   PetscCall(DMSetDimension(*dm, dim));
6319   PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj));
6320   if (interpolate) {
6321     DM idm;
6322 
6323     PetscCall(DMPlexInterpolate(*dm, &idm));
6324     PetscCall(DMDestroy(dm));
6325     *dm = idm;
6326   }
6327   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
6328   if (vertexSF) *vertexSF = sfVert;
6329   else PetscCall(PetscSFDestroy(&sfVert));
6330   PetscFunctionReturn(PETSC_SUCCESS);
6331 }
6332 
6333 /*@
6334   DMPlexCreateFromCellSectionParallel - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) and supports multiple celltypes
6335 
6336   Collective
6337 
6338   Input Parameters:
6339 + comm         - The communicator
6340 . dim          - The topological dimension of the mesh
6341 . numCells     - The number of cells owned by this process
6342 . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`
6343 . NVertices    - The global number of vertices, or `PETSC_DECIDE`
6344 . cellSection  - The `PetscSection` giving the number of vertices for each cell (layout of cells)
6345 . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
6346 . cells        - An array of the global vertex numbers for each cell
6347 . spaceDim     - The spatial dimension used for coordinates
6348 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6349 
6350   Output Parameters:
6351 + dm          - The `DM`
6352 . vertexSF    - (Optional) `PetscSF` describing complete vertex ownership
6353 - verticesAdj - (Optional) vertex adjacency array, must be freed by user
6354 
6355   Level: intermediate
6356 
6357   Notes:
6358   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
6359   `DMPlexBuildFromCellSectionParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`
6360 
6361   See `DMPlexBuildFromCellSectionParallel()` for an example and details about the topology-related parameters.
6362 
6363   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.
6364 
6365 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
6366 @*/
DMPlexCreateFromCellSectionParallel(MPI_Comm comm,PetscInt dim,PetscInt numCells,PetscInt numVertices,PetscInt NVertices,PetscSection cellSection,PetscBool interpolate,const PetscInt cells[],PetscInt spaceDim,const PetscReal vertexCoords[],PeOp PetscSF * vertexSF,PeOp PetscInt * verticesAdj[],DM * dm)6367 PetscErrorCode DMPlexCreateFromCellSectionParallel(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdj[], DM *dm)
6368 {
6369   PetscSF sfVert;
6370 
6371   PetscFunctionBegin;
6372   PetscCall(DMCreate(comm, dm));
6373   PetscCall(DMSetType(*dm, DMPLEX));
6374   PetscValidLogicalCollectiveInt(*dm, dim, 2);
6375   PetscValidLogicalCollectiveInt(*dm, spaceDim, 9);
6376   PetscCall(DMSetDimension(*dm, dim));
6377   PetscCall(DMPlexBuildFromCellSectionParallel(*dm, numCells, numVertices, NVertices, cellSection, cells, &sfVert, verticesAdj));
6378   if (interpolate) {
6379     DM idm;
6380 
6381     PetscCall(DMPlexInterpolate(*dm, &idm));
6382     PetscCall(DMDestroy(dm));
6383     *dm = idm;
6384   }
6385   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
6386   if (vertexSF) *vertexSF = sfVert;
6387   else PetscCall(PetscSFDestroy(&sfVert));
6388   PetscFunctionReturn(PETSC_SUCCESS);
6389 }
6390 
6391 /*@
6392   DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)
6393 
6394   Collective; No Fortran Support
6395 
6396   Input Parameters:
6397 + dm          - The `DM`
6398 . numCells    - The number of cells owned by this process
6399 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE`
6400 . numCorners  - The number of vertices for each cell
6401 - cells       - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell
6402 
6403   Level: advanced
6404 
6405   Notes:
6406   Two triangles sharing a face
6407 .vb
6408 
6409         2
6410       / | \
6411      /  |  \
6412     /   |   \
6413    0  0 | 1  3
6414     \   |   /
6415      \  |  /
6416       \ | /
6417         1
6418 .ve
6419   would have input
6420 .vb
6421   numCells = 2, numVertices = 4
6422   cells = [0 1 2  1 3 2]
6423 .ve
6424   which would result in the `DMPLEX`
6425 .vb
6426 
6427         4
6428       / | \
6429      /  |  \
6430     /   |   \
6431    2  0 | 1  5
6432     \   |   /
6433      \  |  /
6434       \ | /
6435         3
6436 .ve
6437 
6438   If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1.
6439 
6440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()`
6441 @*/
DMPlexBuildFromCellList(DM dm,PetscInt numCells,PetscInt numVertices,PetscInt numCorners,const PetscInt cells[])6442 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[])
6443 {
6444   PetscInt *cones, c, p, dim;
6445 
6446   PetscFunctionBegin;
6447   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6448   PetscCall(DMGetDimension(dm, &dim));
6449   /* Get/check global number of vertices */
6450   {
6451     PetscInt       NVerticesInCells, i;
6452     const PetscInt len = numCells * numCorners;
6453 
6454     /* NVerticesInCells = max(cells) + 1 */
6455     NVerticesInCells = PETSC_INT_MIN;
6456     for (i = 0; i < len; i++)
6457       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
6458     ++NVerticesInCells;
6459 
6460     if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells;
6461     else
6462       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);
6463   }
6464   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
6465   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
6466   PetscCall(DMSetUp(dm));
6467   PetscCall(DMPlexGetCones(dm, &cones));
6468   for (c = 0; c < numCells; ++c) {
6469     for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells;
6470   }
6471   PetscCall(DMPlexSymmetrize(dm));
6472   PetscCall(DMPlexStratify(dm));
6473   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6474   PetscFunctionReturn(PETSC_SUCCESS);
6475 }
6476 
6477 /*@
6478   DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)
6479 
6480   Collective
6481 
6482   Input Parameters:
6483 + dm           - The `DM`
6484 . spaceDim     - The spatial dimension used for coordinates
6485 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6486 
6487   Level: advanced
6488 
6489 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()`
6490 @*/
DMPlexBuildCoordinatesFromCellList(DM dm,PetscInt spaceDim,const PetscReal vertexCoords[])6491 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[])
6492 {
6493   PetscSection coordSection;
6494   Vec          coordinates;
6495   DM           cdm;
6496   PetscScalar *coords;
6497   PetscInt     v, vStart, vEnd, d;
6498 
6499   PetscFunctionBegin;
6500   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
6501   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
6502   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
6503   PetscCall(DMSetCoordinateDim(dm, spaceDim));
6504   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6505   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6506   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
6507   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
6508   for (v = vStart; v < vEnd; ++v) {
6509     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
6510     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
6511   }
6512   PetscCall(PetscSectionSetUp(coordSection));
6513 
6514   PetscCall(DMGetCoordinateDM(dm, &cdm));
6515   PetscCall(DMCreateLocalVector(cdm, &coordinates));
6516   PetscCall(VecSetBlockSize(coordinates, spaceDim));
6517   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
6518   PetscCall(VecGetArrayWrite(coordinates, &coords));
6519   for (v = 0; v < vEnd - vStart; ++v) {
6520     for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d];
6521   }
6522   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
6523   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
6524   PetscCall(VecDestroy(&coordinates));
6525   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
6526   PetscFunctionReturn(PETSC_SUCCESS);
6527 }
6528 
6529 /*@
6530   DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input
6531 
6532   Collective
6533 
6534   Input Parameters:
6535 + comm         - The communicator
6536 . dim          - The topological dimension of the mesh
6537 . numCells     - The number of cells, only on process 0
6538 . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0
6539 . numCorners   - The number of vertices for each cell, only on process 0
6540 . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
6541 . cells        - An array of $ numCells \times numCorners$ numbers, the vertices for each cell, only on process 0
6542 . spaceDim     - The spatial dimension used for coordinates
6543 - vertexCoords - An array of $ numVertices \times spaceDim$ numbers, the coordinates of each vertex, only on process 0
6544 
6545   Output Parameter:
6546 . dm - The `DM`, which only has points on process 0
6547 
6548   Level: intermediate
6549 
6550   Notes:
6551   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`,
6552   `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()`
6553 
6554   See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters.
6555   See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters.
6556   See `DMPlexCreateFromCellListParallelPetsc()` for parallel input
6557 
6558 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
6559 @*/
DMPlexCreateFromCellListPetsc(MPI_Comm comm,PetscInt dim,PetscInt numCells,PetscInt numVertices,PetscInt numCorners,PetscBool interpolate,const PetscInt cells[],PetscInt spaceDim,const PetscReal vertexCoords[],DM * dm)6560 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)
6561 {
6562   PetscMPIInt rank;
6563 
6564   PetscFunctionBegin;
6565   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.");
6566   PetscCallMPI(MPI_Comm_rank(comm, &rank));
6567   PetscCall(DMCreate(comm, dm));
6568   PetscCall(DMSetType(*dm, DMPLEX));
6569   PetscCall(DMSetDimension(*dm, dim));
6570   if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells));
6571   else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL));
6572   if (interpolate) {
6573     DM idm;
6574 
6575     PetscCall(DMPlexInterpolate(*dm, &idm));
6576     PetscCall(DMDestroy(dm));
6577     *dm = idm;
6578   }
6579   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords));
6580   else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL));
6581   PetscFunctionReturn(PETSC_SUCCESS);
6582 }
6583 
6584 /*@
6585   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM`
6586 
6587   Input Parameters:
6588 + dm               - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()`
6589 . depth            - The depth of the DAG
6590 . numPoints        - Array of size $ depth + 1 $ containing the number of points at each `depth`
6591 . coneSize         - The cone size of each point
6592 . cones            - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
6593 . coneOrientations - The orientation of each cone point
6594 - vertexCoords     - An array of $ numPoints[0] \times spacedim $ numbers representing the coordinates of each vertex, with `spacedim` the value set via `DMSetCoordinateDim()`
6595 
6596   Output Parameter:
6597 . dm - The `DM`
6598 
6599   Level: advanced
6600 
6601   Note:
6602   Two triangles sharing a face would have input
6603 .vb
6604   depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
6605   cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
6606  vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
6607 .ve
6608   which would result in the DMPlex
6609 .vb
6610         4
6611       / | \
6612      /  |  \
6613     /   |   \
6614    2  0 | 1  5
6615     \   |   /
6616      \  |  /
6617       \ | /
6618         3
6619 .ve
6620   Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()`
6621 
6622   Developer Note:
6623   This does not create anything so should not have create in the name.
6624 
6625 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
6626 @*/
DMPlexCreateFromDAG(DM dm,PetscInt depth,const PetscInt numPoints[],const PetscInt coneSize[],const PetscInt cones[],const PetscInt coneOrientations[],const PetscScalar vertexCoords[])6627 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
6628 {
6629   Vec          coordinates;
6630   PetscSection coordSection;
6631   PetscScalar *coords;
6632   PetscInt     coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;
6633 
6634   PetscFunctionBegin;
6635   PetscCall(DMGetDimension(dm, &dim));
6636   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
6637   PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim);
6638   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
6639   PetscCall(DMPlexSetChart(dm, pStart, pEnd));
6640   for (p = pStart; p < pEnd; ++p) {
6641     PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart]));
6642     if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart;
6643   }
6644   PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]);
6645   PetscCall(DMSetUp(dm)); /* Allocate space for cones */
6646   for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) {
6647     PetscCall(DMPlexSetCone(dm, p, &cones[off]));
6648     PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off]));
6649   }
6650   PetscCall(DMPlexSymmetrize(dm));
6651   PetscCall(DMPlexStratify(dm));
6652   /* Build coordinates */
6653   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6654   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6655   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed));
6656   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0]));
6657   for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) {
6658     PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed));
6659     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed));
6660   }
6661   PetscCall(PetscSectionSetUp(coordSection));
6662   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
6663   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
6664   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
6665   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
6666   PetscCall(VecSetBlockSize(coordinates, PetscMax(dimEmbed, 1)));
6667   PetscCall(VecSetType(coordinates, VECSTANDARD));
6668   if (vertexCoords) {
6669     PetscCall(VecGetArray(coordinates, &coords));
6670     for (v = 0; v < numPoints[0]; ++v) {
6671       PetscInt off;
6672 
6673       PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off));
6674       for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d];
6675     }
6676   }
6677   PetscCall(VecRestoreArray(coordinates, &coords));
6678   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
6679   PetscCall(VecDestroy(&coordinates));
6680   PetscFunctionReturn(PETSC_SUCCESS);
6681 }
6682 
6683 /*
6684   DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file.
6685 
6686   Collective
6687 
6688 + comm        - The MPI communicator
6689 . filename    - Name of the .dat file
6690 - interpolate - Create faces and edges in the mesh
6691 
6692   Output Parameter:
6693 . dm  - The `DM` object representing the mesh
6694 
6695   Level: beginner
6696 
6697   Note:
6698   The format is the simplest possible:
6699 .vb
6700   dim Ne Nv Nc Nl
6701   v_1 v_2 ... v_Nc
6702   ...
6703   x y z marker_1 ... marker_Nl
6704 .ve
6705 
6706   Developer Note:
6707   Should use a `PetscViewer` not a filename
6708 
6709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
6710 */
DMPlexCreateCellVertexFromFile(MPI_Comm comm,const char filename[],PetscBool interpolate,DM * dm)6711 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
6712 {
6713   DMLabel      marker;
6714   PetscViewer  viewer;
6715   Vec          coordinates;
6716   PetscSection coordSection;
6717   PetscScalar *coords;
6718   char         line[PETSC_MAX_PATH_LEN];
6719   PetscInt     cdim, coordSize, v, c, d;
6720   PetscMPIInt  rank;
6721   int          snum, dim, Nv, Nc, Ncn, Nl;
6722 
6723   PetscFunctionBegin;
6724   PetscCallMPI(MPI_Comm_rank(comm, &rank));
6725   PetscCall(PetscViewerCreate(comm, &viewer));
6726   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
6727   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
6728   PetscCall(PetscViewerFileSetName(viewer, filename));
6729   if (rank == 0) {
6730     PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING));
6731     snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl);
6732     PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
6733   } else {
6734     Nc = Nv = Ncn = Nl = 0;
6735   }
6736   PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
6737   cdim = dim;
6738   PetscCall(DMCreate(comm, dm));
6739   PetscCall(DMSetType(*dm, DMPLEX));
6740   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
6741   PetscCall(DMSetDimension(*dm, dim));
6742   PetscCall(DMSetCoordinateDim(*dm, cdim));
6743   /* Read topology */
6744   if (rank == 0) {
6745     char     format[PETSC_MAX_PATH_LEN];
6746     PetscInt cone[8];
6747     int      vbuf[8], v;
6748 
6749     for (c = 0; c < Ncn; ++c) {
6750       format[c * 3 + 0] = '%';
6751       format[c * 3 + 1] = 'd';
6752       format[c * 3 + 2] = ' ';
6753     }
6754     format[Ncn * 3 - 1] = '\0';
6755     for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn));
6756     PetscCall(DMSetUp(*dm));
6757     for (c = 0; c < Nc; ++c) {
6758       PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING));
6759       switch (Ncn) {
6760       case 2:
6761         snum = sscanf(line, format, &vbuf[0], &vbuf[1]);
6762         break;
6763       case 3:
6764         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]);
6765         break;
6766       case 4:
6767         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]);
6768         break;
6769       case 6:
6770         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]);
6771         break;
6772       case 8:
6773         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]);
6774         break;
6775       default:
6776         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn);
6777       }
6778       PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
6779       for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc;
6780       /* Hexahedra are inverted */
6781       if (Ncn == 8) {
6782         PetscInt tmp = cone[1];
6783         cone[1]      = cone[3];
6784         cone[3]      = tmp;
6785       }
6786       PetscCall(DMPlexSetCone(*dm, c, cone));
6787     }
6788   }
6789   PetscCall(DMPlexSymmetrize(*dm));
6790   PetscCall(DMPlexStratify(*dm));
6791   /* Read coordinates */
6792   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
6793   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6794   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
6795   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
6796   for (v = Nc; v < Nc + Nv; ++v) {
6797     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
6798     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
6799   }
6800   PetscCall(PetscSectionSetUp(coordSection));
6801   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
6802   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
6803   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
6804   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
6805   PetscCall(VecSetBlockSize(coordinates, cdim));
6806   PetscCall(VecSetType(coordinates, VECSTANDARD));
6807   PetscCall(VecGetArray(coordinates, &coords));
6808   if (rank == 0) {
6809     char   format[PETSC_MAX_PATH_LEN];
6810     double x[3];
6811     int    l, val[3];
6812 
6813     if (Nl) {
6814       for (l = 0; l < Nl; ++l) {
6815         format[l * 3 + 0] = '%';
6816         format[l * 3 + 1] = 'd';
6817         format[l * 3 + 2] = ' ';
6818       }
6819       format[Nl * 3 - 1] = '\0';
6820       PetscCall(DMCreateLabel(*dm, "marker"));
6821       PetscCall(DMGetLabel(*dm, "marker", &marker));
6822     }
6823     for (v = 0; v < Nv; ++v) {
6824       PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING));
6825       snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]);
6826       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
6827       switch (Nl) {
6828       case 0:
6829         snum = 0;
6830         break;
6831       case 1:
6832         snum = sscanf(line, format, &val[0]);
6833         break;
6834       case 2:
6835         snum = sscanf(line, format, &val[0], &val[1]);
6836         break;
6837       case 3:
6838         snum = sscanf(line, format, &val[0], &val[1], &val[2]);
6839         break;
6840       default:
6841         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl);
6842       }
6843       PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
6844       for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d];
6845       for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l]));
6846     }
6847   }
6848   PetscCall(VecRestoreArray(coordinates, &coords));
6849   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
6850   PetscCall(VecDestroy(&coordinates));
6851   PetscCall(PetscViewerDestroy(&viewer));
6852   if (interpolate) {
6853     DM      idm;
6854     DMLabel bdlabel;
6855 
6856     PetscCall(DMPlexInterpolate(*dm, &idm));
6857     PetscCall(DMDestroy(dm));
6858     *dm = idm;
6859 
6860     if (!Nl) {
6861       PetscCall(DMCreateLabel(*dm, "marker"));
6862       PetscCall(DMGetLabel(*dm, "marker", &bdlabel));
6863       PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel));
6864       PetscCall(DMPlexLabelComplete(*dm, bdlabel));
6865     }
6866   }
6867   PetscFunctionReturn(PETSC_SUCCESS);
6868 }
6869 
6870 /*
6871   DMPlexCreateSTLFromFile - Create a `DMPLEX` mesh from an STL file.
6872 
6873   Collective
6874 
6875 + comm        - The MPI communicator
6876 . filename    - Name of the .dat file
6877 - interpolate - Create faces and edges in the mesh
6878 
6879   Output Parameter:
6880 . dm  - The `DM` object representing the mesh
6881 
6882   Level: beginner
6883 
6884   Notes:
6885   The binary format is:
6886 .vb
6887   UINT8[80]    - Header               - 80 bytes
6888   UINT32       - Number of triangles  - 04 bytes
6889   foreach triangle                    - 50 bytes
6890     REAL32[3] - Normal vector         - 12 bytes
6891     REAL32[3] - Vertex 1              - 12 bytes
6892     REAL32[3] - Vertex 2              - 12 bytes
6893     REAL32[3] - Vertex 3              - 12 bytes
6894     UINT16    - Attribute byte count  - 02 bytes
6895   end
6896 .ve
6897 
6898   The format is here <https://en.wikipedia.org/wiki/STL_(file_format)>
6899 
6900 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
6901 */
DMPlexCreateSTLFromFile(MPI_Comm comm,const char filename[],PetscBool interpolate,DM * dm)6902 static PetscErrorCode DMPlexCreateSTLFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
6903 {
6904   PetscViewer  viewer;
6905   Vec          coordinates;
6906   PetscSection coordSection;
6907   PetscScalar *coords;
6908   PetscInt     coordSize;
6909   char         line[PETSC_MAX_PATH_LEN];
6910   PetscBT      bt;
6911   float       *trialCoords = NULL;
6912   PetscInt    *cells       = NULL;
6913   PetscBool    isascii;
6914   PetscMPIInt  rank;
6915   PetscInt     Nc, Nv, nv = 0;
6916 
6917   PetscFunctionBegin;
6918   PetscCallMPI(MPI_Comm_rank(comm, &rank));
6919   PetscCall(PetscViewerCreate(comm, &viewer));
6920   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERBINARY));
6921   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
6922   PetscCall(PetscViewerFileSetName(viewer, filename));
6923   if (rank == 0) {
6924     int num;
6925 
6926     PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_CHAR));
6927     line[5] = 0;
6928     PetscCall(PetscStrncmp(line, "solid", 5, &isascii));
6929     PetscCheck(!isascii, comm, PETSC_ERR_SUP, "No support for ASCII yet");
6930     PetscCall(PetscViewerRead(viewer, line, 75, NULL, PETSC_CHAR));
6931     line[75] = 0;
6932     PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_INT32));
6933     PetscCall(PetscByteSwap(&num, PETSC_INT32, 1));
6934     Nc = num;
6935     // Read facet coordinates
6936     PetscCall(PetscMalloc1(Nc * 9, &trialCoords));
6937     for (PetscInt c = 0; c < Nc; ++c) {
6938       double    normal[3];
6939       short int unused;
6940 
6941       PetscCall(PetscViewerRead(viewer, normal, 3, NULL, PETSC_FLOAT));
6942       PetscCall(PetscViewerRead(viewer, &trialCoords[c * 9 + 0], 9, NULL, PETSC_FLOAT));
6943       PetscCall(PetscByteSwap(&trialCoords[c * 9 + 0], PETSC_FLOAT, 9));
6944       PetscCall(PetscViewerRead(viewer, &unused, 1, NULL, PETSC_SHORT));
6945     }
6946     PetscCall(PetscMalloc1(Nc * 3, &cells));
6947     // Find unique vertices
6948     PetscCall(PetscBTCreate(Nc * 3, &bt));
6949     PetscCall(PetscBTMemzero(Nc * 3, bt));
6950     PetscCall(PetscBTSet(bt, 0));
6951     PetscCall(PetscBTSet(bt, 1));
6952     PetscCall(PetscBTSet(bt, 2));
6953     Nv       = 0;
6954     cells[0] = Nc + Nv++;
6955     cells[1] = Nc + Nv++;
6956     cells[2] = Nc + Nv++;
6957     for (PetscInt v = 3; v < Nc * 3; ++v) {
6958       PetscBool match = PETSC_FALSE;
6959 
6960       for (PetscInt w = 0, x = 0; w < v; ++w) {
6961         if (PetscBTLookup(bt, w)) {
6962           if (trialCoords[v * 3 + 0] == trialCoords[w * 3 + 0] && trialCoords[v * 3 + 1] == trialCoords[w * 3 + 1] && trialCoords[v * 3 + 2] == trialCoords[w * 3 + 2]) {
6963             match    = PETSC_TRUE;
6964             cells[v] = Nc + x;
6965             break;
6966           }
6967           ++x;
6968         }
6969       }
6970       if (!match) {
6971         PetscCall(PetscBTSet(bt, v));
6972         cells[v] = Nc + Nv++;
6973       }
6974     }
6975   } else {
6976     Nc = Nv = 0;
6977   }
6978   for (PetscInt v = 3; v < Nc * 3; ++v) PetscCheck(cells[v] < Nc + Nv, comm, PETSC_ERR_PLIB, "Invalid cells[%" PetscInt_FMT "]: %" PetscInt_FMT, v, cells[v]);
6979   PetscCall(DMCreate(comm, dm));
6980   PetscCall(DMSetType(*dm, DMPLEX));
6981   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
6982   PetscCall(DMSetDimension(*dm, 2));
6983   PetscCall(DMSetCoordinateDim(*dm, 3));
6984   for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, 3));
6985   PetscCall(DMSetUp(*dm));
6986   for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMPlexSetCone(*dm, c, &cells[c * 3]));
6987   PetscCall(PetscFree(cells));
6988   PetscCall(DMPlexSymmetrize(*dm));
6989   PetscCall(DMPlexStratify(*dm));
6990 
6991   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
6992   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6993   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
6994   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
6995   for (PetscInt v = Nc; v < Nc + Nv; ++v) {
6996     PetscCall(PetscSectionSetDof(coordSection, v, 3));
6997     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
6998   }
6999   PetscCall(PetscSectionSetUp(coordSection));
7000   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
7001   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
7002   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
7003   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
7004   PetscCall(VecSetBlockSize(coordinates, 3));
7005   PetscCall(VecSetType(coordinates, VECSTANDARD));
7006   PetscCall(VecGetArray(coordinates, &coords));
7007   for (PetscInt tv = 0; tv < Nc * 3; ++tv) {
7008     if (PetscBTLookup(bt, tv)) {
7009       for (PetscInt d = 0; d < 3; ++d) coords[nv * 3 + d] = trialCoords[tv * 3 + d];
7010       ++nv;
7011     }
7012   }
7013   PetscCheck(nv == Nv, comm, PETSC_ERR_PLIB, "Number of vertices copied %" PetscInt_FMT " != %" PetscInt_FMT " number of mesh vertices", nv, Nv);
7014   PetscCall(PetscFree(trialCoords));
7015   PetscCall(PetscBTDestroy(&bt));
7016   PetscCall(VecRestoreArray(coordinates, &coords));
7017   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
7018   PetscCall(VecDestroy(&coordinates));
7019   PetscCall(PetscViewerDestroy(&viewer));
7020   if (interpolate) {
7021     DM idm;
7022 
7023     PetscCall(DMPlexInterpolate(*dm, &idm));
7024     PetscCall(DMDestroy(dm));
7025     *dm = idm;
7026   }
7027   PetscFunctionReturn(PETSC_SUCCESS);
7028 }
7029 
7030 /*
7031   DMPlexCreateShapefile - Create a `DMPLEX` mesh from the ESRI Shapefile format.
7032 
7033   Collective
7034 
7035 + comm   - The MPI communicator
7036 - viewer - `PetscViewer` for the .shp file
7037 
7038   Output Parameter:
7039 . dm - The `DM` object representing the mesh
7040 
7041   Level: beginner
7042 
7043   Note:
7044   The format is specified at [Wikipedia](https://en.wikipedia.org/wiki/Shapefile) and [ESRI](https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf).
7045 
7046 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
7047 */
DMPlexCreateShapefile(MPI_Comm comm,PetscViewer viewer,DM * dm)7048 static PetscErrorCode DMPlexCreateShapefile(MPI_Comm comm, PetscViewer viewer, DM *dm)
7049 {
7050   Vec          coordinates;
7051   PetscSection coordSection;
7052   PetscScalar *coords;
7053   PetscInt     cdim   = 2, coordSize;
7054   int          dim    = 1, Nv, Nc, vOff;
7055   double      *points = NULL;
7056   double       mbr[4], zb[2], mb[2];
7057   PetscMPIInt  rank;
7058 
7059   PetscFunctionBegin;
7060   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7061   if (rank == 0) {
7062     PetscInt cnt;
7063     int      magic, dummy[5], len, version, shtype, totlen = 0;
7064 
7065     // Read header
7066     PetscCall(PetscViewerBinaryRead(viewer, &magic, 1, &cnt, PETSC_INT32));
7067     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 0-3");
7068     PetscCheck(magic == 0x0000270a, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: invalid magic number %X", magic);
7069     PetscCall(PetscViewerBinaryRead(viewer, dummy, 5, &cnt, PETSC_INT32));
7070     PetscCheck(cnt == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 4-23");
7071     PetscCall(PetscViewerBinaryRead(viewer, &len, 1, &cnt, PETSC_INT32));
7072     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 24-27");
7073     PetscCall(PetscViewerBinaryRead(viewer, &version, 1, &cnt, PETSC_INT32));
7074     PetscCall(PetscByteSwap(&version, PETSC_INT32, 1));
7075     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 28-31");
7076     PetscCall(PetscInfo(viewer, "Shapefile: version %d file length %d\n", version, len));
7077     PetscCall(PetscViewerBinaryRead(viewer, &shtype, 1, &cnt, PETSC_INT32));
7078     PetscCall(PetscByteSwap(&shtype, PETSC_INT32, 1));
7079     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 32-35");
7080     PetscCall(PetscInfo(viewer, "Shapefile: shape type %d\n", shtype));
7081     PetscCall(PetscViewerBinaryRead(viewer, mbr, 4, &cnt, PETSC_DOUBLE));
7082     PetscCall(PetscByteSwap(mbr, PETSC_DOUBLE, 4));
7083     PetscCheck(cnt == 4, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 36-67");
7084     PetscCall(PetscInfo(viewer, "Shapefile: minimum bounding rectangle (%g, %g) -- (%g, %g)\n", mbr[0], mbr[1], mbr[2], mbr[3]));
7085     PetscCall(PetscViewerBinaryRead(viewer, zb, 2, &cnt, PETSC_DOUBLE));
7086     PetscCall(PetscByteSwap(zb, PETSC_DOUBLE, 2));
7087     PetscCheck(cnt == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 68-83");
7088     PetscCall(PetscInfo(viewer, "Shapefile: Z bounds (%g) -- (%g)\n", zb[0], zb[1]));
7089     PetscCall(PetscViewerBinaryRead(viewer, mb, 2, &cnt, PETSC_DOUBLE));
7090     PetscCall(PetscByteSwap(mb, PETSC_DOUBLE, 2));
7091     PetscCheck(cnt == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 84-99");
7092     PetscCall(PetscInfo(viewer, "Shapefile: M bounds (%g) -- (%g)\n", mb[0], mb[1]));
7093     totlen += 100;
7094     {
7095       int    rnum, rlen, rshtype, rnpart, rnp;
7096       double rmbr[4];
7097       int   *partOffsets;
7098 
7099       // Read record header
7100       PetscCall(PetscViewerBinaryRead(viewer, &rnum, 1, &cnt, PETSC_INT32));
7101       PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record header bytes 0-3");
7102       PetscCall(PetscViewerBinaryRead(viewer, &rlen, 1, &cnt, PETSC_INT32));
7103       PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record header bytes 4-7");
7104       PetscCall(PetscInfo(viewer, "Shapefile: record %d length %d\n", rnum, rlen));
7105       totlen += 8;
7106       // Read record
7107       PetscCall(PetscViewerBinaryRead(viewer, &rshtype, 1, &cnt, PETSC_INT32));
7108       PetscCall(PetscByteSwap(&rshtype, PETSC_INT32, 1));
7109       PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 0-3");
7110       PetscCall(PetscInfo(viewer, "Shapefile: record shape type %d\n", rshtype));
7111       totlen += 4;
7112       switch (rshtype) {
7113       case 5: // Polygon
7114         PetscCall(PetscViewerBinaryRead(viewer, rmbr, 4, &cnt, PETSC_DOUBLE));
7115         PetscCall(PetscByteSwap(rmbr, PETSC_DOUBLE, 4));
7116         PetscCheck(cnt == 4, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 4-35");
7117         PetscCall(PetscInfo(viewer, "Shapefile: record minimum bounding rectangle (%g, %g) -- (%g, %g)\n", rmbr[0], rmbr[1], rmbr[2], rmbr[3]));
7118         PetscCall(PetscViewerBinaryRead(viewer, &rnpart, 1, &cnt, PETSC_INT32));
7119         PetscCall(PetscByteSwap(&rnpart, PETSC_INT32, 1));
7120         PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 36-39");
7121         PetscCall(PetscInfo(viewer, "Shapefile: record shape number of parts %d\n", rnpart));
7122         PetscCall(PetscViewerBinaryRead(viewer, &rnp, 1, &cnt, PETSC_INT32));
7123         PetscCall(PetscByteSwap(&rnp, PETSC_INT32, 1));
7124         PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 36-39");
7125         PetscCall(PetscInfo(viewer, "Shapefile: record shape number of points %d\n", rnp));
7126         totlen += 40;
7127         PetscCall(PetscMalloc1(rnpart, &partOffsets));
7128         PetscCall(PetscViewerBinaryRead(viewer, partOffsets, rnpart, &cnt, PETSC_INT32));
7129         PetscCall(PetscByteSwap(partOffsets, PETSC_INT32, rnpart));
7130         PetscCheck(cnt == rnpart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record part offsets");
7131         totlen += 4 * rnpart;
7132         PetscCall(PetscMalloc1(rnp * 2, &points));
7133         PetscCall(PetscViewerBinaryRead(viewer, points, rnp * 2, &cnt, PETSC_DOUBLE));
7134         PetscCall(PetscByteSwap(points, PETSC_DOUBLE, rnp * 2));
7135         PetscCheck(cnt == rnp * 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record points");
7136         totlen += 8 * rnp * 2;
7137         PetscCheck(totlen == 2 * len, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unable to parse Shapefile file: only support a single object: %d != %d", totlen, 2 * len);
7138         // Only get the last polygon now
7139         vOff = partOffsets[rnpart - 1];
7140         Nv   = rnp - vOff;
7141         Nc   = Nv - 1;
7142         PetscCall(PetscInfo(viewer, "Shapefile: record first polygon size %d totlen %d\n", Nv, totlen));
7143         PetscCall(PetscFree(partOffsets));
7144         break;
7145       default:
7146         PetscCheck(0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support polygons right now");
7147       }
7148     }
7149   } else {
7150     Nc = Nv = vOff = 0;
7151   }
7152   PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
7153   PetscCall(DMCreate(comm, dm));
7154   PetscCall(DMSetType(*dm, DMPLEX));
7155   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
7156   PetscCall(DMSetDimension(*dm, dim));
7157   PetscCall(DMSetCoordinateDim(*dm, cdim));
7158   // Topology of a circle
7159   if (rank == 0) {
7160     for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, 2));
7161     PetscCall(DMSetUp(*dm));
7162     for (PetscInt c = 0; c < Nc; ++c) {
7163       PetscInt cone[2] = {Nc + c, Nc + c + 1};
7164 
7165       PetscCall(DMPlexSetCone(*dm, c, cone));
7166     }
7167   }
7168   PetscCall(DMPlexSymmetrize(*dm));
7169   PetscCall(DMPlexStratify(*dm));
7170   // Set coordinates
7171   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
7172   PetscCall(PetscSectionSetNumFields(coordSection, 1));
7173   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
7174   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
7175   for (PetscInt v = Nc; v < Nc + Nv; ++v) {
7176     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
7177     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
7178   }
7179   PetscCall(PetscSectionSetUp(coordSection));
7180   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
7181   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
7182   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
7183   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
7184   PetscCall(VecSetBlockSize(coordinates, cdim));
7185   PetscCall(VecSetType(coordinates, VECSTANDARD));
7186   PetscCall(VecGetArray(coordinates, &coords));
7187   for (PetscInt v = 0; v < Nv; ++v) {
7188     coords[v * cdim + 0] = points[(v + vOff) * cdim + 0] - mbr[0];
7189     coords[v * cdim + 1] = points[(v + vOff) * cdim + 1] - mbr[1];
7190   }
7191   PetscCall(PetscFree(points));
7192   PetscCall(VecRestoreArray(coordinates, &coords));
7193   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
7194   PetscCall(VecDestroy(&coordinates));
7195   PetscFunctionReturn(PETSC_SUCCESS);
7196 }
7197 
7198 /*
7199   DMPlexCreateShapefileFromFile - Create a `DMPLEX` mesh from the ESRI Shapefile format.
7200 
7201   Collective
7202 
7203 + comm     - The MPI communicator
7204 . filename - Name of the .shp file
7205 
7206   Output Parameter:
7207 . dm - The `DM` object representing the mesh
7208 
7209   Level: beginner
7210 
7211   Note:
7212   The format is specified at [Wikipedia](https://en.wikipedia.org/wiki/Shapefile) and [ESRI](https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf).
7213 
7214 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
7215 */
DMPlexCreateShapefileFromFile(MPI_Comm comm,const char filename[],DM * dm)7216 static PetscErrorCode DMPlexCreateShapefileFromFile(MPI_Comm comm, const char filename[], DM *dm)
7217 {
7218   PetscViewer viewer;
7219 
7220   PetscFunctionBegin;
7221   PetscCall(PetscViewerCreate(comm, &viewer));
7222   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERBINARY));
7223   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
7224   PetscCall(PetscViewerFileSetName(viewer, filename));
7225   PetscCall(DMPlexCreateShapefile(comm, viewer, dm));
7226   PetscCall(PetscViewerDestroy(&viewer));
7227   PetscFunctionReturn(PETSC_SUCCESS);
7228 }
7229 
7230 /*@
7231   DMPlexCreateFromFile - This takes a filename and produces a `DM`
7232 
7233   Collective
7234 
7235   Input Parameters:
7236 + comm        - The communicator
7237 . filename    - A file name
7238 . plexname    - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats
7239 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
7240 
7241   Output Parameter:
7242 . dm - The `DM`
7243 
7244   Options Database Key:
7245 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5
7246 
7247   Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. `-dm_plex_create_viewer_hdf5_collective`
7248 
7249   Level: beginner
7250 
7251   Notes:
7252   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
7253   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
7254   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
7255   The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally
7256   calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats.
7257 
7258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()`
7259 @*/
DMPlexCreateFromFile(MPI_Comm comm,const char filename[],const char plexname[],PetscBool interpolate,DM * dm)7260 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm)
7261 {
7262   const char  extGmsh[]      = ".msh";
7263   const char  extGmsh2[]     = ".msh2";
7264   const char  extGmsh4[]     = ".msh4";
7265   const char  extCGNS[]      = ".cgns";
7266   const char  extExodus[]    = ".exo";
7267   const char  extExodus_e[]  = ".e";
7268   const char  extGenesis[]   = ".gen";
7269   const char  extFluent[]    = ".cas";
7270   const char  extHDF5[]      = ".h5";
7271   const char  extXDMFHDF5[]  = ".xdmf.h5";
7272   const char  extPLY[]       = ".ply";
7273   const char  extEGADSlite[] = ".egadslite";
7274   const char  extEGADS[]     = ".egads";
7275   const char  extIGES[]      = ".igs";
7276   const char  extIGES2[]     = ".iges";
7277   const char  extSTEP[]      = ".stp";
7278   const char  extSTEP2[]     = ".step";
7279   const char  extBREP[]      = ".brep";
7280   const char  extCV[]        = ".dat";
7281   const char  extSTL[]       = ".stl";
7282   const char  extSHP[]       = ".shp";
7283   size_t      len;
7284   PetscBool   isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSlite, isEGADS, isIGES, isIGES2, isSTEP, isSTEP2, isBREP, isCV, isSTL, isSHP, isXDMFHDF5;
7285   PetscMPIInt rank;
7286 
7287   PetscFunctionBegin;
7288   PetscAssertPointer(filename, 2);
7289   if (plexname) PetscAssertPointer(plexname, 3);
7290   PetscAssertPointer(dm, 5);
7291   PetscCall(DMInitializePackage());
7292   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0));
7293   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7294   PetscCall(PetscStrlen(filename, &len));
7295   PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");
7296 
7297 #define CheckExtension(extension__, is_extension__) \
7298   do { \
7299     PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \
7300     /* don't count the null-terminator at the end */ \
7301     const size_t ext_len = sizeof(extension__) - 1; \
7302     if (len < ext_len) { \
7303       is_extension__ = PETSC_FALSE; \
7304     } else { \
7305       PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \
7306     } \
7307   } while (0)
7308 
7309   CheckExtension(extGmsh, isGmsh);
7310   CheckExtension(extGmsh2, isGmsh2);
7311   CheckExtension(extGmsh4, isGmsh4);
7312   CheckExtension(extCGNS, isCGNS);
7313   CheckExtension(extExodus, isExodus);
7314   if (!isExodus) CheckExtension(extExodus_e, isExodus);
7315   CheckExtension(extGenesis, isGenesis);
7316   CheckExtension(extFluent, isFluent);
7317   CheckExtension(extHDF5, isHDF5);
7318   CheckExtension(extPLY, isPLY);
7319   CheckExtension(extEGADSlite, isEGADSlite);
7320   CheckExtension(extEGADS, isEGADS);
7321   CheckExtension(extIGES, isIGES);
7322   CheckExtension(extIGES2, isIGES2);
7323   CheckExtension(extSTEP, isSTEP);
7324   CheckExtension(extSTEP2, isSTEP2);
7325   CheckExtension(extBREP, isBREP);
7326   CheckExtension(extCV, isCV);
7327   CheckExtension(extSTL, isSTL);
7328   CheckExtension(extSHP, isSHP);
7329   CheckExtension(extXDMFHDF5, isXDMFHDF5);
7330 
7331 #undef CheckExtension
7332 
7333   if (isGmsh || isGmsh2 || isGmsh4) {
7334     PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm));
7335   } else if (isCGNS) {
7336     PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm));
7337   } else if (isExodus || isGenesis) {
7338     PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm));
7339   } else if (isFluent) {
7340     PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm));
7341   } else if (isHDF5) {
7342     PetscViewer viewer;
7343 
7344     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
7345     PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL));
7346     PetscCall(PetscViewerCreate(comm, &viewer));
7347     PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5));
7348     PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_"));
7349     PetscCall(PetscViewerSetFromOptions(viewer));
7350     PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
7351     PetscCall(PetscViewerFileSetName(viewer, filename));
7352 
7353     PetscCall(DMCreate(comm, dm));
7354     PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
7355     PetscCall(DMSetType(*dm, DMPLEX));
7356     if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF));
7357     PetscCall(DMLoad(*dm, viewer));
7358     if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer));
7359     PetscCall(PetscViewerDestroy(&viewer));
7360 
7361     if (interpolate) {
7362       DM idm;
7363 
7364       PetscCall(DMPlexInterpolate(*dm, &idm));
7365       PetscCall(DMDestroy(dm));
7366       *dm = idm;
7367     }
7368   } else if (isPLY) {
7369     PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm));
7370   } else if (isEGADSlite || isEGADS || isIGES || isIGES2 || isSTEP || isSTEP2 || isBREP) {
7371     PetscCall(DMPlexCreateGeomFromFile(comm, filename, dm, isEGADSlite));
7372 
7373     if (!interpolate) {
7374       DM udm;
7375 
7376       PetscCall(DMPlexUninterpolate(*dm, &udm));
7377       PetscCall(DMDestroy(dm));
7378       *dm = udm;
7379     }
7380   } else if (isCV) {
7381     PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm));
7382   } else if (isSTL) {
7383     PetscCall(DMPlexCreateSTLFromFile(comm, filename, interpolate, dm));
7384   } else if (isSHP) {
7385     PetscCall(DMPlexCreateShapefileFromFile(comm, filename, dm));
7386   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
7387   PetscCall(PetscStrlen(plexname, &len));
7388   if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
7389   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0));
7390   PetscFunctionReturn(PETSC_SUCCESS);
7391 }
7392 
7393 /*@
7394   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.
7395 
7396   Input Parameters:
7397 + tr     - The `DMPlexTransform`
7398 - prefix - An options prefix, or NULL
7399 
7400   Output Parameter:
7401 . dm - The `DM`
7402 
7403   Level: beginner
7404 
7405   Notes:
7406   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.
7407 
7408 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
7409 @*/
DMPlexCreateEphemeral(DMPlexTransform tr,const char prefix[],DM * dm)7410 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm)
7411 {
7412   DM           bdm, bcdm, cdm;
7413   Vec          coordinates, coordinatesNew;
7414   PetscSection cs;
7415   PetscInt     cdim, Nl;
7416 
7417   PetscFunctionBegin;
7418   PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm));
7419   PetscCall(DMSetType(*dm, DMPLEX));
7420   ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL;
7421   // Handle coordinates
7422   PetscCall(DMPlexTransformGetDM(tr, &bdm));
7423   PetscCall(DMPlexTransformSetDimensions(tr, bdm, *dm));
7424   PetscCall(DMGetCoordinateDim(*dm, &cdim));
7425   PetscCall(DMGetCoordinateDM(bdm, &bcdm));
7426   PetscCall(DMGetCoordinateDM(*dm, &cdm));
7427   PetscCall(DMCopyDisc(bcdm, cdm));
7428   PetscCall(DMGetLocalSection(cdm, &cs));
7429   PetscCall(PetscSectionSetNumFields(cs, 1));
7430   PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim));
7431   PetscCall(DMGetCoordinatesLocal(bdm, &coordinates));
7432   PetscCall(VecDuplicate(coordinates, &coordinatesNew));
7433   PetscCall(VecCopy(coordinates, coordinatesNew));
7434   PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew));
7435   PetscCall(VecDestroy(&coordinatesNew));
7436 
7437   PetscCall(PetscObjectReference((PetscObject)tr));
7438   PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr));
7439   ((DM_Plex *)(*dm)->data)->tr = tr;
7440   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
7441   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix));
7442   PetscCall(DMSetFromOptions(*dm));
7443 
7444   PetscCall(DMGetNumLabels(bdm, &Nl));
7445   for (PetscInt l = 0; l < Nl; ++l) {
7446     DMLabel     label, labelNew;
7447     const char *lname;
7448     PetscBool   isDepth, isCellType;
7449 
7450     PetscCall(DMGetLabelName(bdm, l, &lname));
7451     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
7452     if (isDepth) continue;
7453     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
7454     if (isCellType) continue;
7455     PetscCall(DMCreateLabel(*dm, lname));
7456     PetscCall(DMGetLabel(bdm, lname, &label));
7457     PetscCall(DMGetLabel(*dm, lname, &labelNew));
7458     PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL));
7459     PetscCall(DMLabelEphemeralSetLabel(labelNew, label));
7460     PetscCall(DMLabelEphemeralSetTransform(labelNew, tr));
7461     PetscCall(DMLabelSetUp(labelNew));
7462   }
7463   PetscFunctionReturn(PETSC_SUCCESS);
7464 }
7465