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), ¢roidsf));
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(¢roidsf));
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, °ree, NULL));
5372 PetscCall(DMGetCoordinateDegree_Internal(dm, °));
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