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