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