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