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 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) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate)); 1295 else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0])); 1296 else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate)); 1297 else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity)); 1298 if (!interpolate && dim > 1 && !simplex) { 1299 DM udm; 1300 1301 PetscCall(DMPlexUninterpolate(dm, &udm)); 1302 PetscCall(DMPlexCopyCoordinates(dm, udm)); 1303 PetscCall(DMPlexReplace_Internal(dm, &udm)); 1304 } 1305 PetscFunctionReturn(0); 1306 } 1307 1308 /*@C 1309 DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra). 1310 1311 Collective 1312 1313 Input Parameters: 1314 + comm - The communicator for the `DM` object 1315 . dim - The spatial dimension 1316 . simplex - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells 1317 . faces - Number of faces per dimension, or NULL for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 1318 . lower - The lower left corner, or NULL for (0, 0, 0) 1319 . upper - The upper right corner, or NULL for (1, 1, 1) 1320 . periodicity - The boundary type for the X,Y,Z direction, or NULL for `DM_BOUNDARY_NONE` 1321 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 1322 1323 Output Parameter: 1324 . dm - The `DM` object 1325 1326 Level: beginner 1327 1328 Note: 1329 To customize this mesh using options, use 1330 .vb 1331 DMCreate(comm, &dm); 1332 DMSetType(dm, DMPLEX); 1333 DMSetFromOptions(dm); 1334 .ve 1335 and use the options in `DMSetFromOptions()`. 1336 1337 Here is the numbering returned for 2 faces in each direction for tensor cells: 1338 .vb 1339 10---17---11---18----12 1340 | | | 1341 | | | 1342 20 2 22 3 24 1343 | | | 1344 | | | 1345 7---15----8---16----9 1346 | | | 1347 | | | 1348 19 0 21 1 23 1349 | | | 1350 | | | 1351 4---13----5---14----6 1352 .ve 1353 and for simplicial cells 1354 .vb 1355 14----8---15----9----16 1356 |\ 5 |\ 7 | 1357 | \ | \ | 1358 13 2 14 3 15 1359 | 4 \ | 6 \ | 1360 | \ | \ | 1361 11----6---12----7----13 1362 |\ |\ | 1363 | \ 1 | \ 3 | 1364 10 0 11 1 12 1365 | 0 \ | 2 \ | 1366 | \ | \ | 1367 8----4----9----5----10 1368 .ve 1369 1370 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()` 1371 @*/ 1372 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) 1373 { 1374 PetscInt fac[3] = {1, 1, 1}; 1375 PetscReal low[3] = {0, 0, 0}; 1376 PetscReal upp[3] = {1, 1, 1}; 1377 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 1378 1379 PetscFunctionBegin; 1380 PetscCall(DMCreate(comm, dm)); 1381 PetscCall(DMSetType(*dm, DMPLEX)); 1382 PetscCall(DMPlexCreateBoxMesh_Internal(*dm, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate)); 1383 if (periodicity) PetscCall(DMLocalizeCoordinates(*dm)); 1384 PetscFunctionReturn(0); 1385 } 1386 1387 static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[]) 1388 { 1389 DM bdm, vol; 1390 PetscInt i; 1391 1392 PetscFunctionBegin; 1393 for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported"); 1394 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm)); 1395 PetscCall(DMSetType(bdm, DMPLEX)); 1396 PetscCall(DMSetDimension(bdm, 2)); 1397 PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE)); 1398 PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, NULL, NULL, &vol)); 1399 PetscCall(DMDestroy(&bdm)); 1400 PetscCall(DMPlexReplace_Internal(dm, &vol)); 1401 if (lower[2] != 0.0) { 1402 Vec v; 1403 PetscScalar *x; 1404 PetscInt cDim, n; 1405 1406 PetscCall(DMGetCoordinatesLocal(dm, &v)); 1407 PetscCall(VecGetBlockSize(v, &cDim)); 1408 PetscCall(VecGetLocalSize(v, &n)); 1409 PetscCall(VecGetArray(v, &x)); 1410 x += cDim; 1411 for (i = 0; i < n; i += cDim) x[i] += lower[2]; 1412 PetscCall(VecRestoreArray(v, &x)); 1413 PetscCall(DMSetCoordinatesLocal(dm, v)); 1414 } 1415 PetscFunctionReturn(0); 1416 } 1417 1418 /*@ 1419 DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tesselating the (x,y) plane and extruding in the third direction using wedge cells. 1420 1421 Collective 1422 1423 Input Parameters: 1424 + comm - The communicator for the `DM` object 1425 . faces - Number of faces per dimension, or NULL for (1, 1, 1) 1426 . lower - The lower left corner, or NULL for (0, 0, 0) 1427 . upper - The upper right corner, or NULL for (1, 1, 1) 1428 . periodicity - The boundary type for the X,Y,Z direction, or NULL for `DM_BOUNDARY_NONE` 1429 . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first 1430 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 1431 1432 Output Parameter: 1433 . dm - The `DM` object 1434 1435 Level: beginner 1436 1437 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 1438 @*/ 1439 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm) 1440 { 1441 PetscInt fac[3] = {1, 1, 1}; 1442 PetscReal low[3] = {0, 0, 0}; 1443 PetscReal upp[3] = {1, 1, 1}; 1444 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 1445 1446 PetscFunctionBegin; 1447 PetscCall(DMCreate(comm, dm)); 1448 PetscCall(DMSetType(*dm, DMPLEX)); 1449 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt)); 1450 if (!interpolate) { 1451 DM udm; 1452 1453 PetscCall(DMPlexUninterpolate(*dm, &udm)); 1454 PetscCall(DMPlexReplace_Internal(*dm, &udm)); 1455 } 1456 if (periodicity) PetscCall(DMLocalizeCoordinates(*dm)); 1457 PetscFunctionReturn(0); 1458 } 1459 1460 /* 1461 DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension. 1462 Ordering is lexicographic with lowest index as least significant in ordering. 1463 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}. 1464 1465 Input Parameters: 1466 + len - The length of the tuple 1467 . max - The maximum for each dimension, so values are in [0, max) 1468 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition 1469 1470 Output Parameter: 1471 . tup - A tuple of len integers whose entries are at most 'max' 1472 1473 Level: developer 1474 1475 .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal() 1476 */ 1477 static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[]) 1478 { 1479 PetscInt i; 1480 1481 PetscFunctionBegin; 1482 for (i = 0; i < len; ++i) { 1483 if (tup[i] < max[i] - 1) { 1484 break; 1485 } else { 1486 tup[i] = 0; 1487 } 1488 } 1489 if (i == len) tup[i - 1] = max[i - 1]; 1490 else ++tup[i]; 1491 PetscFunctionReturn(0); 1492 } 1493 1494 static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[]) 1495 { 1496 PetscInt i, idx = tup[len - 1]; 1497 1498 for (i = len - 2; i >= 0; --i) { 1499 idx *= max[i]; 1500 idx += tup[i]; 1501 } 1502 return idx; 1503 } 1504 1505 static PetscErrorCode DestroyExtent_Private(void *extent) 1506 { 1507 return PetscFree(extent); 1508 } 1509 1510 static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], const DMBoundaryType bd[]) 1511 { 1512 Vec coordinates; 1513 PetscSection coordSection; 1514 DMLabel cutLabel = NULL; 1515 PetscBool cutMarker = PETSC_FALSE; 1516 PetscBool periodic = PETSC_FALSE; 1517 PetscInt numCells = 1, c; 1518 PetscInt numVertices = 1, v; 1519 PetscScalar *coords; 1520 PetscInt *vertices, *vert, *vtmp, *supp, cone[2]; 1521 PetscInt d, e, cell = 0, coordSize; 1522 PetscMPIInt rank; 1523 1524 PetscFunctionBegin; 1525 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1526 PetscCall(DMSetDimension(dm, dim)); 1527 PetscCall(PetscCalloc4(dim, &vertices, dim, &vert, dim, &vtmp, 2 * dim, &supp)); 1528 PetscCall(DMCreateLabel(dm, "marker")); 1529 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL)); 1530 for (d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE; 1531 if (periodic && cutMarker) { 1532 PetscCall(DMCreateLabel(dm, "periodic_cut")); 1533 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 1534 } 1535 for (d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Hypercubic mesh must be periodic now"); 1536 for (d = 0; d < dim; ++d) { 1537 vertices[d] = edges[d]; 1538 numVertices *= vertices[d]; 1539 } 1540 numCells = numVertices * dim; 1541 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 1542 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2)); 1543 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim)); 1544 /* TODO Loop over boundary and reset support sizes */ 1545 PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */ 1546 /* Build cell cones and vertex supports */ 1547 PetscCall(DMCreateLabel(dm, "celltype")); 1548 while (vert[dim - 1] < vertices[dim - 1]) { 1549 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells; 1550 PetscInt s = 0; 1551 1552 PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex); 1553 for (d = 0; d < dim; ++d) PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]); 1554 PetscPrintf(PETSC_COMM_SELF, "\n"); 1555 PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT)); 1556 for (d = 0; d < dim; ++d) { 1557 for (e = 0; e < dim; ++e) vtmp[e] = vert[e]; 1558 vtmp[d] = (vert[d] + 1) % vertices[d]; 1559 cone[0] = vertex; 1560 cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells; 1561 PetscPrintf(PETSC_COMM_SELF, " Vertex %" PetscInt_FMT ":", cone[1]); 1562 for (e = 0; e < dim; ++e) PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vtmp[e]); 1563 PetscPrintf(PETSC_COMM_SELF, "\n"); 1564 PetscCall(DMPlexSetCone(dm, cell, cone)); 1565 PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT)); 1566 PetscPrintf(PETSC_COMM_SELF, " Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1]); 1567 ++cell; 1568 } 1569 for (d = 0; d < dim; ++d) { 1570 for (e = 0; e < dim; ++e) vtmp[e] = vert[e]; 1571 vtmp[d] = (vert[d] + vertices[d] - 1) % vertices[d]; 1572 supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d; 1573 supp[s++] = (vertex - numCells) * dim + d; 1574 PetscCall(DMPlexSetSupport(dm, vertex, supp)); 1575 } 1576 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 1577 } 1578 PetscCall(DMPlexStratify(dm)); 1579 /* Build coordinates */ 1580 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1581 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1582 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 1583 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 1584 for (v = numCells; v < numCells + numVertices; ++v) { 1585 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 1586 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 1587 } 1588 PetscCall(PetscSectionSetUp(coordSection)); 1589 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 1590 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 1591 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 1592 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 1593 PetscCall(VecSetBlockSize(coordinates, dim)); 1594 PetscCall(VecSetType(coordinates, VECSTANDARD)); 1595 PetscCall(VecGetArray(coordinates, &coords)); 1596 for (d = 0; d < dim; ++d) vert[d] = 0; 1597 while (vert[dim - 1] < vertices[dim - 1]) { 1598 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert); 1599 1600 for (d = 0; d < dim; ++d) coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / vertices[d]) * vert[d]; 1601 PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex); 1602 for (d = 0; d < dim; ++d) PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]); 1603 for (d = 0; d < dim; ++d) PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(coords[vertex * dim + d])); 1604 PetscPrintf(PETSC_COMM_SELF, "\n"); 1605 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 1606 } 1607 PetscCall(VecRestoreArray(coordinates, &coords)); 1608 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1609 PetscCall(VecDestroy(&coordinates)); 1610 PetscCall(PetscFree4(vertices, vert, vtmp, supp)); 1611 //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper)); 1612 // Attach the extent 1613 { 1614 PetscContainer c; 1615 PetscInt *extent; 1616 1617 PetscCall(PetscMalloc1(dim, &extent)); 1618 for (PetscInt d = 0; d < dim; ++d) extent[d] = edges[d]; 1619 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c)); 1620 PetscCall(PetscContainerSetUserDestroy(c, DestroyExtent_Private)); 1621 PetscCall(PetscContainerSetPointer(c, extent)); 1622 PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c)); 1623 PetscCall(PetscContainerDestroy(&c)); 1624 } 1625 PetscFunctionReturn(0); 1626 } 1627 1628 /*@C 1629 DMPlexCreateHypercubicMesh - Creates a peridoic mesh on the tensor product of unit intervals using only vertices and edges. 1630 1631 Collective 1632 1633 Input Parameters: 1634 + comm - The communicator for the DM object 1635 . dim - The spatial dimension 1636 . edges - Number of edges per dimension, or NULL for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 1637 . lower - The lower left corner, or NULL for (0, 0, 0) 1638 - upper - The upper right corner, or NULL for (1, 1, 1) 1639 1640 Output Parameter: 1641 . dm - The DM object 1642 1643 Note: If you want to customize this mesh using options, you just need to 1644 $ DMCreate(comm, &dm); 1645 $ DMSetType(dm, DMPLEX); 1646 $ DMSetFromOptions(dm); 1647 and use the options on the DMSetFromOptions() page. 1648 1649 The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively, 1650 $ 18--0-19--2-20--4-18 1651 $ | | | | 1652 $ 13 15 17 13 1653 $ | | | | 1654 $ 24-12-25-14-26-16-24 1655 $ | | | | 1656 $ 7 9 11 7 1657 $ | | | | 1658 $ 21--6-22--8-23-10-21 1659 $ | | | | 1660 $ 1 3 5 1 1661 $ | | | | 1662 $ 18--0-19--2-20--4-18 1663 1664 Level: beginner 1665 1666 .seealso: DMSetFromOptions(), DMPlexCreateFromFile(), DMPlexCreateHexCylinderMesh(), DMSetType(), DMCreate() 1667 @*/ 1668 PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], DM *dm) 1669 { 1670 PetscInt *edg; 1671 PetscReal *low, *upp; 1672 DMBoundaryType *bdt; 1673 PetscInt d; 1674 1675 PetscFunctionBegin; 1676 PetscCall(DMCreate(comm, dm)); 1677 PetscCall(DMSetType(*dm, DMPLEX)); 1678 PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt)); 1679 for (d = 0; d < dim; ++d) { 1680 edg[d] = edges ? edges[d] : 1; 1681 low[d] = lower ? lower[d] : 0.; 1682 upp[d] = upper ? upper[d] : 1.; 1683 bdt[d] = DM_BOUNDARY_PERIODIC; 1684 } 1685 PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, bdt)); 1686 PetscCall(PetscFree4(edg, low, upp, bdt)); 1687 PetscFunctionReturn(0); 1688 } 1689 1690 /*@C 1691 DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database. 1692 1693 Logically Collective on dm 1694 1695 Input Parameters: 1696 + dm - the DM context 1697 - prefix - the prefix to prepend to all option names 1698 1699 Level: advanced 1700 1701 Note: 1702 A hyphen (-) must NOT be given at the beginning of the prefix name. 1703 The first character of all runtime options is AUTOMATICALLY the hyphen. 1704 1705 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()` 1706 @*/ 1707 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[]) 1708 { 1709 DM_Plex *mesh = (DM_Plex *)dm->data; 1710 1711 PetscFunctionBegin; 1712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1713 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix)); 1714 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix)); 1715 PetscFunctionReturn(0); 1716 } 1717 1718 /* Remap geometry to cylinder 1719 TODO: This only works for a single refinement, then it is broken 1720 1721 Interior square: Linear interpolation is correct 1722 The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing 1723 such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance 1724 1725 phi = arctan(y/x) 1726 d_close = sqrt(1/8 + 1/4 sin^2(phi)) 1727 d_far = sqrt(1/2 + sin^2(phi)) 1728 1729 so we remap them using 1730 1731 x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close) 1732 y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close) 1733 1734 If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y. 1735 */ 1736 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[]) 1737 { 1738 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 1739 const PetscReal ds2 = 0.5 * dis; 1740 1741 if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) { 1742 f0[0] = u[0]; 1743 f0[1] = u[1]; 1744 } else { 1745 PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc; 1746 1747 x = PetscRealPart(u[0]); 1748 y = PetscRealPart(u[1]); 1749 phi = PetscAtan2Real(y, x); 1750 sinp = PetscSinReal(phi); 1751 cosp = PetscCosReal(phi); 1752 if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) { 1753 dc = PetscAbsReal(ds2 / sinp); 1754 df = PetscAbsReal(dis / sinp); 1755 xc = ds2 * x / PetscAbsReal(y); 1756 yc = ds2 * PetscSignReal(y); 1757 } else { 1758 dc = PetscAbsReal(ds2 / cosp); 1759 df = PetscAbsReal(dis / cosp); 1760 xc = ds2 * PetscSignReal(x); 1761 yc = ds2 * y / PetscAbsReal(x); 1762 } 1763 f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc); 1764 f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc); 1765 } 1766 f0[2] = u[2]; 1767 } 1768 1769 static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ) 1770 { 1771 const PetscInt dim = 3; 1772 PetscInt numCells, numVertices; 1773 PetscMPIInt rank; 1774 1775 PetscFunctionBegin; 1776 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1777 PetscCall(DMSetDimension(dm, dim)); 1778 /* Create topology */ 1779 { 1780 PetscInt cone[8], c; 1781 1782 numCells = rank == 0 ? 5 : 0; 1783 numVertices = rank == 0 ? 16 : 0; 1784 if (periodicZ == DM_BOUNDARY_PERIODIC) { 1785 numCells *= 3; 1786 numVertices = rank == 0 ? 24 : 0; 1787 } 1788 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 1789 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8)); 1790 PetscCall(DMSetUp(dm)); 1791 if (rank == 0) { 1792 if (periodicZ == DM_BOUNDARY_PERIODIC) { 1793 cone[0] = 15; 1794 cone[1] = 18; 1795 cone[2] = 17; 1796 cone[3] = 16; 1797 cone[4] = 31; 1798 cone[5] = 32; 1799 cone[6] = 33; 1800 cone[7] = 34; 1801 PetscCall(DMPlexSetCone(dm, 0, cone)); 1802 cone[0] = 16; 1803 cone[1] = 17; 1804 cone[2] = 24; 1805 cone[3] = 23; 1806 cone[4] = 32; 1807 cone[5] = 36; 1808 cone[6] = 37; 1809 cone[7] = 33; /* 22 25 26 21 */ 1810 PetscCall(DMPlexSetCone(dm, 1, cone)); 1811 cone[0] = 18; 1812 cone[1] = 27; 1813 cone[2] = 24; 1814 cone[3] = 17; 1815 cone[4] = 34; 1816 cone[5] = 33; 1817 cone[6] = 37; 1818 cone[7] = 38; 1819 PetscCall(DMPlexSetCone(dm, 2, cone)); 1820 cone[0] = 29; 1821 cone[1] = 27; 1822 cone[2] = 18; 1823 cone[3] = 15; 1824 cone[4] = 35; 1825 cone[5] = 31; 1826 cone[6] = 34; 1827 cone[7] = 38; 1828 PetscCall(DMPlexSetCone(dm, 3, cone)); 1829 cone[0] = 29; 1830 cone[1] = 15; 1831 cone[2] = 16; 1832 cone[3] = 23; 1833 cone[4] = 35; 1834 cone[5] = 36; 1835 cone[6] = 32; 1836 cone[7] = 31; 1837 PetscCall(DMPlexSetCone(dm, 4, cone)); 1838 1839 cone[0] = 31; 1840 cone[1] = 34; 1841 cone[2] = 33; 1842 cone[3] = 32; 1843 cone[4] = 19; 1844 cone[5] = 22; 1845 cone[6] = 21; 1846 cone[7] = 20; 1847 PetscCall(DMPlexSetCone(dm, 5, cone)); 1848 cone[0] = 32; 1849 cone[1] = 33; 1850 cone[2] = 37; 1851 cone[3] = 36; 1852 cone[4] = 22; 1853 cone[5] = 25; 1854 cone[6] = 26; 1855 cone[7] = 21; 1856 PetscCall(DMPlexSetCone(dm, 6, cone)); 1857 cone[0] = 34; 1858 cone[1] = 38; 1859 cone[2] = 37; 1860 cone[3] = 33; 1861 cone[4] = 20; 1862 cone[5] = 21; 1863 cone[6] = 26; 1864 cone[7] = 28; 1865 PetscCall(DMPlexSetCone(dm, 7, cone)); 1866 cone[0] = 35; 1867 cone[1] = 38; 1868 cone[2] = 34; 1869 cone[3] = 31; 1870 cone[4] = 30; 1871 cone[5] = 19; 1872 cone[6] = 20; 1873 cone[7] = 28; 1874 PetscCall(DMPlexSetCone(dm, 8, cone)); 1875 cone[0] = 35; 1876 cone[1] = 31; 1877 cone[2] = 32; 1878 cone[3] = 36; 1879 cone[4] = 30; 1880 cone[5] = 25; 1881 cone[6] = 22; 1882 cone[7] = 19; 1883 PetscCall(DMPlexSetCone(dm, 9, cone)); 1884 1885 cone[0] = 19; 1886 cone[1] = 20; 1887 cone[2] = 21; 1888 cone[3] = 22; 1889 cone[4] = 15; 1890 cone[5] = 16; 1891 cone[6] = 17; 1892 cone[7] = 18; 1893 PetscCall(DMPlexSetCone(dm, 10, cone)); 1894 cone[0] = 22; 1895 cone[1] = 21; 1896 cone[2] = 26; 1897 cone[3] = 25; 1898 cone[4] = 16; 1899 cone[5] = 23; 1900 cone[6] = 24; 1901 cone[7] = 17; 1902 PetscCall(DMPlexSetCone(dm, 11, cone)); 1903 cone[0] = 20; 1904 cone[1] = 28; 1905 cone[2] = 26; 1906 cone[3] = 21; 1907 cone[4] = 18; 1908 cone[5] = 17; 1909 cone[6] = 24; 1910 cone[7] = 27; 1911 PetscCall(DMPlexSetCone(dm, 12, cone)); 1912 cone[0] = 30; 1913 cone[1] = 28; 1914 cone[2] = 20; 1915 cone[3] = 19; 1916 cone[4] = 29; 1917 cone[5] = 15; 1918 cone[6] = 18; 1919 cone[7] = 27; 1920 PetscCall(DMPlexSetCone(dm, 13, cone)); 1921 cone[0] = 30; 1922 cone[1] = 19; 1923 cone[2] = 22; 1924 cone[3] = 25; 1925 cone[4] = 29; 1926 cone[5] = 23; 1927 cone[6] = 16; 1928 cone[7] = 15; 1929 PetscCall(DMPlexSetCone(dm, 14, cone)); 1930 } else { 1931 cone[0] = 5; 1932 cone[1] = 8; 1933 cone[2] = 7; 1934 cone[3] = 6; 1935 cone[4] = 9; 1936 cone[5] = 12; 1937 cone[6] = 11; 1938 cone[7] = 10; 1939 PetscCall(DMPlexSetCone(dm, 0, cone)); 1940 cone[0] = 6; 1941 cone[1] = 7; 1942 cone[2] = 14; 1943 cone[3] = 13; 1944 cone[4] = 12; 1945 cone[5] = 15; 1946 cone[6] = 16; 1947 cone[7] = 11; 1948 PetscCall(DMPlexSetCone(dm, 1, cone)); 1949 cone[0] = 8; 1950 cone[1] = 17; 1951 cone[2] = 14; 1952 cone[3] = 7; 1953 cone[4] = 10; 1954 cone[5] = 11; 1955 cone[6] = 16; 1956 cone[7] = 18; 1957 PetscCall(DMPlexSetCone(dm, 2, cone)); 1958 cone[0] = 19; 1959 cone[1] = 17; 1960 cone[2] = 8; 1961 cone[3] = 5; 1962 cone[4] = 20; 1963 cone[5] = 9; 1964 cone[6] = 10; 1965 cone[7] = 18; 1966 PetscCall(DMPlexSetCone(dm, 3, cone)); 1967 cone[0] = 19; 1968 cone[1] = 5; 1969 cone[2] = 6; 1970 cone[3] = 13; 1971 cone[4] = 20; 1972 cone[5] = 15; 1973 cone[6] = 12; 1974 cone[7] = 9; 1975 PetscCall(DMPlexSetCone(dm, 4, cone)); 1976 } 1977 } 1978 PetscCall(DMPlexSymmetrize(dm)); 1979 PetscCall(DMPlexStratify(dm)); 1980 } 1981 /* Create cube geometry */ 1982 { 1983 Vec coordinates; 1984 PetscSection coordSection; 1985 PetscScalar *coords; 1986 PetscInt coordSize, v; 1987 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 1988 const PetscReal ds2 = dis / 2.0; 1989 1990 /* Build coordinates */ 1991 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1992 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1993 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 1994 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 1995 for (v = numCells; v < numCells + numVertices; ++v) { 1996 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 1997 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 1998 } 1999 PetscCall(PetscSectionSetUp(coordSection)); 2000 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2001 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2002 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2003 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2004 PetscCall(VecSetBlockSize(coordinates, dim)); 2005 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2006 PetscCall(VecGetArray(coordinates, &coords)); 2007 if (rank == 0) { 2008 coords[0 * dim + 0] = -ds2; 2009 coords[0 * dim + 1] = -ds2; 2010 coords[0 * dim + 2] = 0.0; 2011 coords[1 * dim + 0] = ds2; 2012 coords[1 * dim + 1] = -ds2; 2013 coords[1 * dim + 2] = 0.0; 2014 coords[2 * dim + 0] = ds2; 2015 coords[2 * dim + 1] = ds2; 2016 coords[2 * dim + 2] = 0.0; 2017 coords[3 * dim + 0] = -ds2; 2018 coords[3 * dim + 1] = ds2; 2019 coords[3 * dim + 2] = 0.0; 2020 coords[4 * dim + 0] = -ds2; 2021 coords[4 * dim + 1] = -ds2; 2022 coords[4 * dim + 2] = 1.0; 2023 coords[5 * dim + 0] = -ds2; 2024 coords[5 * dim + 1] = ds2; 2025 coords[5 * dim + 2] = 1.0; 2026 coords[6 * dim + 0] = ds2; 2027 coords[6 * dim + 1] = ds2; 2028 coords[6 * dim + 2] = 1.0; 2029 coords[7 * dim + 0] = ds2; 2030 coords[7 * dim + 1] = -ds2; 2031 coords[7 * dim + 2] = 1.0; 2032 coords[8 * dim + 0] = dis; 2033 coords[8 * dim + 1] = -dis; 2034 coords[8 * dim + 2] = 0.0; 2035 coords[9 * dim + 0] = dis; 2036 coords[9 * dim + 1] = dis; 2037 coords[9 * dim + 2] = 0.0; 2038 coords[10 * dim + 0] = dis; 2039 coords[10 * dim + 1] = -dis; 2040 coords[10 * dim + 2] = 1.0; 2041 coords[11 * dim + 0] = dis; 2042 coords[11 * dim + 1] = dis; 2043 coords[11 * dim + 2] = 1.0; 2044 coords[12 * dim + 0] = -dis; 2045 coords[12 * dim + 1] = dis; 2046 coords[12 * dim + 2] = 0.0; 2047 coords[13 * dim + 0] = -dis; 2048 coords[13 * dim + 1] = dis; 2049 coords[13 * dim + 2] = 1.0; 2050 coords[14 * dim + 0] = -dis; 2051 coords[14 * dim + 1] = -dis; 2052 coords[14 * dim + 2] = 0.0; 2053 coords[15 * dim + 0] = -dis; 2054 coords[15 * dim + 1] = -dis; 2055 coords[15 * dim + 2] = 1.0; 2056 if (periodicZ == DM_BOUNDARY_PERIODIC) { 2057 /* 15 31 19 */ coords[16 * dim + 0] = -ds2; 2058 coords[16 * dim + 1] = -ds2; 2059 coords[16 * dim + 2] = 0.5; 2060 /* 16 32 22 */ coords[17 * dim + 0] = ds2; 2061 coords[17 * dim + 1] = -ds2; 2062 coords[17 * dim + 2] = 0.5; 2063 /* 17 33 21 */ coords[18 * dim + 0] = ds2; 2064 coords[18 * dim + 1] = ds2; 2065 coords[18 * dim + 2] = 0.5; 2066 /* 18 34 20 */ coords[19 * dim + 0] = -ds2; 2067 coords[19 * dim + 1] = ds2; 2068 coords[19 * dim + 2] = 0.5; 2069 /* 29 35 30 */ coords[20 * dim + 0] = -dis; 2070 coords[20 * dim + 1] = -dis; 2071 coords[20 * dim + 2] = 0.5; 2072 /* 23 36 25 */ coords[21 * dim + 0] = dis; 2073 coords[21 * dim + 1] = -dis; 2074 coords[21 * dim + 2] = 0.5; 2075 /* 24 37 26 */ coords[22 * dim + 0] = dis; 2076 coords[22 * dim + 1] = dis; 2077 coords[22 * dim + 2] = 0.5; 2078 /* 27 38 28 */ coords[23 * dim + 0] = -dis; 2079 coords[23 * dim + 1] = dis; 2080 coords[23 * dim + 2] = 0.5; 2081 } 2082 } 2083 PetscCall(VecRestoreArray(coordinates, &coords)); 2084 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2085 PetscCall(VecDestroy(&coordinates)); 2086 } 2087 /* Create periodicity */ 2088 if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) { 2089 PetscReal L[3] = {-1., -1., 0.}; 2090 PetscReal maxCell[3] = {-1., -1., 0.}; 2091 PetscReal lower[3] = {0.0, 0.0, 0.0}; 2092 PetscReal upper[3] = {1.0, 1.0, 1.5}; 2093 PetscInt numZCells = 3; 2094 2095 L[2] = upper[2] - lower[2]; 2096 maxCell[2] = 1.1 * (L[2] / numZCells); 2097 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 2098 } 2099 { 2100 DM cdm; 2101 PetscDS cds; 2102 PetscScalar c[2] = {1.0, 1.0}; 2103 2104 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, snapToCylinder)); 2105 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2106 PetscCall(DMGetDS(cdm, &cds)); 2107 PetscCall(PetscDSSetConstants(cds, 2, c)); 2108 } 2109 /* Wait for coordinate creation before doing in-place modification */ 2110 PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2111 PetscFunctionReturn(0); 2112 } 2113 2114 /*@ 2115 DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra. 2116 2117 Collective 2118 2119 Input Parameters: 2120 + comm - The communicator for the `DM` object 2121 - periodicZ - The boundary type for the Z direction 2122 2123 Output Parameter: 2124 . dm - The DM object 2125 2126 Level: beginner 2127 2128 Note: 2129 Here is the output numbering looking from the bottom of the cylinder: 2130 .vb 2131 17-----14 2132 | | 2133 | 2 | 2134 | | 2135 17-----8-----7-----14 2136 | | | | 2137 | 3 | 0 | 1 | 2138 | | | | 2139 19-----5-----6-----13 2140 | | 2141 | 4 | 2142 | | 2143 19-----13 2144 2145 and up through the top 2146 2147 18-----16 2148 | | 2149 | 2 | 2150 | | 2151 18----10----11-----16 2152 | | | | 2153 | 3 | 0 | 1 | 2154 | | | | 2155 20-----9----12-----15 2156 | | 2157 | 4 | 2158 | | 2159 20-----15 2160 .ve 2161 2162 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2163 @*/ 2164 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, DM *dm) 2165 { 2166 PetscFunctionBegin; 2167 PetscValidPointer(dm, 3); 2168 PetscCall(DMCreate(comm, dm)); 2169 PetscCall(DMSetType(*dm, DMPLEX)); 2170 PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ)); 2171 PetscFunctionReturn(0); 2172 } 2173 2174 static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate) 2175 { 2176 const PetscInt dim = 3; 2177 PetscInt numCells, numVertices, v; 2178 PetscMPIInt rank; 2179 2180 PetscFunctionBegin; 2181 PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n); 2182 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2183 PetscCall(DMSetDimension(dm, dim)); 2184 /* Must create the celltype label here so that we do not automatically try to compute the types */ 2185 PetscCall(DMCreateLabel(dm, "celltype")); 2186 /* Create topology */ 2187 { 2188 PetscInt cone[6], c; 2189 2190 numCells = rank == 0 ? n : 0; 2191 numVertices = rank == 0 ? 2 * (n + 1) : 0; 2192 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 2193 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6)); 2194 PetscCall(DMSetUp(dm)); 2195 for (c = 0; c < numCells; c++) { 2196 cone[0] = c + n * 1; 2197 cone[1] = (c + 1) % n + n * 1; 2198 cone[2] = 0 + 3 * n; 2199 cone[3] = c + n * 2; 2200 cone[4] = (c + 1) % n + n * 2; 2201 cone[5] = 1 + 3 * n; 2202 PetscCall(DMPlexSetCone(dm, c, cone)); 2203 PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR)); 2204 } 2205 PetscCall(DMPlexSymmetrize(dm)); 2206 PetscCall(DMPlexStratify(dm)); 2207 } 2208 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT)); 2209 /* Create cylinder geometry */ 2210 { 2211 Vec coordinates; 2212 PetscSection coordSection; 2213 PetscScalar *coords; 2214 PetscInt coordSize, c; 2215 2216 /* Build coordinates */ 2217 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2218 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2219 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2220 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2221 for (v = numCells; v < numCells + numVertices; ++v) { 2222 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2223 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2224 } 2225 PetscCall(PetscSectionSetUp(coordSection)); 2226 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2227 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2228 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2229 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2230 PetscCall(VecSetBlockSize(coordinates, dim)); 2231 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2232 PetscCall(VecGetArray(coordinates, &coords)); 2233 for (c = 0; c < numCells; c++) { 2234 coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 2235 coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 2236 coords[(c + 0 * n) * dim + 2] = 1.0; 2237 coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 2238 coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 2239 coords[(c + 1 * n) * dim + 2] = 0.0; 2240 } 2241 if (rank == 0) { 2242 coords[(2 * n + 0) * dim + 0] = 0.0; 2243 coords[(2 * n + 0) * dim + 1] = 0.0; 2244 coords[(2 * n + 0) * dim + 2] = 1.0; 2245 coords[(2 * n + 1) * dim + 0] = 0.0; 2246 coords[(2 * n + 1) * dim + 1] = 0.0; 2247 coords[(2 * n + 1) * dim + 2] = 0.0; 2248 } 2249 PetscCall(VecRestoreArray(coordinates, &coords)); 2250 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2251 PetscCall(VecDestroy(&coordinates)); 2252 } 2253 /* Interpolate */ 2254 if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2255 PetscFunctionReturn(0); 2256 } 2257 2258 /*@ 2259 DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges. 2260 2261 Collective 2262 2263 Input Parameters: 2264 + comm - The communicator for the `DM` object 2265 . n - The number of wedges around the origin 2266 - interpolate - Create edges and faces 2267 2268 Output Parameter: 2269 . dm - The `DM` object 2270 2271 Level: beginner 2272 2273 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2274 @*/ 2275 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm) 2276 { 2277 PetscFunctionBegin; 2278 PetscValidPointer(dm, 4); 2279 PetscCall(DMCreate(comm, dm)); 2280 PetscCall(DMSetType(*dm, DMPLEX)); 2281 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate)); 2282 PetscFunctionReturn(0); 2283 } 2284 2285 static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 2286 { 2287 PetscReal prod = 0.0; 2288 PetscInt i; 2289 for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]); 2290 return PetscSqrtReal(prod); 2291 } 2292 static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 2293 { 2294 PetscReal prod = 0.0; 2295 PetscInt i; 2296 for (i = 0; i < dim; ++i) prod += x[i] * y[i]; 2297 return prod; 2298 } 2299 2300 /* The first constant is the sphere radius */ 2301 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[]) 2302 { 2303 PetscReal r = PetscRealPart(constants[0]); 2304 PetscReal norm2 = 0.0, fac; 2305 PetscInt n = uOff[1] - uOff[0], d; 2306 2307 for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d])); 2308 fac = r / PetscSqrtReal(norm2); 2309 for (d = 0; d < n; ++d) f0[d] = u[d] * fac; 2310 } 2311 2312 static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R) 2313 { 2314 const PetscInt embedDim = dim + 1; 2315 PetscSection coordSection; 2316 Vec coordinates; 2317 PetscScalar *coords; 2318 PetscReal *coordsIn; 2319 PetscInt numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, c, e; 2320 PetscMPIInt rank; 2321 2322 PetscFunctionBegin; 2323 PetscValidLogicalCollectiveBool(dm, simplex, 3); 2324 PetscCall(DMSetDimension(dm, dim)); 2325 PetscCall(DMSetCoordinateDim(dm, dim + 1)); 2326 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2327 switch (dim) { 2328 case 2: 2329 if (simplex) { 2330 const PetscReal radius = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI); 2331 const PetscReal edgeLen = 2.0 / (1.0 + PETSC_PHI) * (R / radius); 2332 const PetscInt degree = 5; 2333 PetscReal vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)}; 2334 PetscInt s[3] = {1, 1, 1}; 2335 PetscInt cone[3]; 2336 PetscInt *graph, p, i, j, k; 2337 2338 vertex[0] *= R / radius; 2339 vertex[1] *= R / radius; 2340 vertex[2] *= R / radius; 2341 numCells = rank == 0 ? 20 : 0; 2342 numVerts = rank == 0 ? 12 : 0; 2343 firstVertex = numCells; 2344 /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of 2345 2346 (0, \pm 1/\phi+1, \pm \phi/\phi+1) 2347 2348 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 2349 length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393. 2350 */ 2351 /* Construct vertices */ 2352 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2353 if (rank == 0) { 2354 for (p = 0, i = 0; p < embedDim; ++p) { 2355 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2356 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2357 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim]; 2358 ++i; 2359 } 2360 } 2361 } 2362 } 2363 /* Construct graph */ 2364 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 2365 for (i = 0; i < numVerts; ++i) { 2366 for (j = 0, k = 0; j < numVerts; ++j) { 2367 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 2368 graph[i * numVerts + j] = 1; 2369 ++k; 2370 } 2371 } 2372 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 2373 } 2374 /* Build Topology */ 2375 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2376 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2377 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2378 /* Cells */ 2379 for (i = 0, c = 0; i < numVerts; ++i) { 2380 for (j = 0; j < i; ++j) { 2381 for (k = 0; k < j; ++k) { 2382 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) { 2383 cone[0] = firstVertex + i; 2384 cone[1] = firstVertex + j; 2385 cone[2] = firstVertex + k; 2386 /* Check orientation */ 2387 { 2388 const PetscInt epsilon[3][3][3] = { 2389 {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 2390 {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 2391 {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 2392 }; 2393 PetscReal normal[3]; 2394 PetscInt e, f; 2395 2396 for (d = 0; d < embedDim; ++d) { 2397 normal[d] = 0.0; 2398 for (e = 0; e < embedDim; ++e) { 2399 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]); 2400 } 2401 } 2402 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 2403 PetscInt tmp = cone[1]; 2404 cone[1] = cone[2]; 2405 cone[2] = tmp; 2406 } 2407 } 2408 PetscCall(DMPlexSetCone(dm, c++, cone)); 2409 } 2410 } 2411 } 2412 } 2413 PetscCall(DMPlexSymmetrize(dm)); 2414 PetscCall(DMPlexStratify(dm)); 2415 PetscCall(PetscFree(graph)); 2416 } else { 2417 /* 2418 12-21--13 2419 | | 2420 25 4 24 2421 | | 2422 12-25--9-16--8-24--13 2423 | | | | 2424 23 5 17 0 15 3 22 2425 | | | | 2426 10-20--6-14--7-19--11 2427 | | 2428 20 1 19 2429 | | 2430 10-18--11 2431 | | 2432 23 2 22 2433 | | 2434 12-21--13 2435 */ 2436 PetscInt cone[4], ornt[4]; 2437 2438 numCells = rank == 0 ? 6 : 0; 2439 numEdges = rank == 0 ? 12 : 0; 2440 numVerts = rank == 0 ? 8 : 0; 2441 firstVertex = numCells; 2442 firstEdge = numCells + numVerts; 2443 /* Build Topology */ 2444 PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts)); 2445 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4)); 2446 for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 2447 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2448 if (rank == 0) { 2449 /* Cell 0 */ 2450 cone[0] = 14; 2451 cone[1] = 15; 2452 cone[2] = 16; 2453 cone[3] = 17; 2454 PetscCall(DMPlexSetCone(dm, 0, cone)); 2455 ornt[0] = 0; 2456 ornt[1] = 0; 2457 ornt[2] = 0; 2458 ornt[3] = 0; 2459 PetscCall(DMPlexSetConeOrientation(dm, 0, ornt)); 2460 /* Cell 1 */ 2461 cone[0] = 18; 2462 cone[1] = 19; 2463 cone[2] = 14; 2464 cone[3] = 20; 2465 PetscCall(DMPlexSetCone(dm, 1, cone)); 2466 ornt[0] = 0; 2467 ornt[1] = 0; 2468 ornt[2] = -1; 2469 ornt[3] = 0; 2470 PetscCall(DMPlexSetConeOrientation(dm, 1, ornt)); 2471 /* Cell 2 */ 2472 cone[0] = 21; 2473 cone[1] = 22; 2474 cone[2] = 18; 2475 cone[3] = 23; 2476 PetscCall(DMPlexSetCone(dm, 2, cone)); 2477 ornt[0] = 0; 2478 ornt[1] = 0; 2479 ornt[2] = -1; 2480 ornt[3] = 0; 2481 PetscCall(DMPlexSetConeOrientation(dm, 2, ornt)); 2482 /* Cell 3 */ 2483 cone[0] = 19; 2484 cone[1] = 22; 2485 cone[2] = 24; 2486 cone[3] = 15; 2487 PetscCall(DMPlexSetCone(dm, 3, cone)); 2488 ornt[0] = -1; 2489 ornt[1] = -1; 2490 ornt[2] = 0; 2491 ornt[3] = -1; 2492 PetscCall(DMPlexSetConeOrientation(dm, 3, ornt)); 2493 /* Cell 4 */ 2494 cone[0] = 16; 2495 cone[1] = 24; 2496 cone[2] = 21; 2497 cone[3] = 25; 2498 PetscCall(DMPlexSetCone(dm, 4, cone)); 2499 ornt[0] = -1; 2500 ornt[1] = -1; 2501 ornt[2] = -1; 2502 ornt[3] = 0; 2503 PetscCall(DMPlexSetConeOrientation(dm, 4, ornt)); 2504 /* Cell 5 */ 2505 cone[0] = 20; 2506 cone[1] = 17; 2507 cone[2] = 25; 2508 cone[3] = 23; 2509 PetscCall(DMPlexSetCone(dm, 5, cone)); 2510 ornt[0] = -1; 2511 ornt[1] = -1; 2512 ornt[2] = -1; 2513 ornt[3] = -1; 2514 PetscCall(DMPlexSetConeOrientation(dm, 5, ornt)); 2515 /* Edges */ 2516 cone[0] = 6; 2517 cone[1] = 7; 2518 PetscCall(DMPlexSetCone(dm, 14, cone)); 2519 cone[0] = 7; 2520 cone[1] = 8; 2521 PetscCall(DMPlexSetCone(dm, 15, cone)); 2522 cone[0] = 8; 2523 cone[1] = 9; 2524 PetscCall(DMPlexSetCone(dm, 16, cone)); 2525 cone[0] = 9; 2526 cone[1] = 6; 2527 PetscCall(DMPlexSetCone(dm, 17, cone)); 2528 cone[0] = 10; 2529 cone[1] = 11; 2530 PetscCall(DMPlexSetCone(dm, 18, cone)); 2531 cone[0] = 11; 2532 cone[1] = 7; 2533 PetscCall(DMPlexSetCone(dm, 19, cone)); 2534 cone[0] = 6; 2535 cone[1] = 10; 2536 PetscCall(DMPlexSetCone(dm, 20, cone)); 2537 cone[0] = 12; 2538 cone[1] = 13; 2539 PetscCall(DMPlexSetCone(dm, 21, cone)); 2540 cone[0] = 13; 2541 cone[1] = 11; 2542 PetscCall(DMPlexSetCone(dm, 22, cone)); 2543 cone[0] = 10; 2544 cone[1] = 12; 2545 PetscCall(DMPlexSetCone(dm, 23, cone)); 2546 cone[0] = 13; 2547 cone[1] = 8; 2548 PetscCall(DMPlexSetCone(dm, 24, cone)); 2549 cone[0] = 12; 2550 cone[1] = 9; 2551 PetscCall(DMPlexSetCone(dm, 25, cone)); 2552 } 2553 PetscCall(DMPlexSymmetrize(dm)); 2554 PetscCall(DMPlexStratify(dm)); 2555 /* Build coordinates */ 2556 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2557 if (rank == 0) { 2558 coordsIn[0 * embedDim + 0] = -R; 2559 coordsIn[0 * embedDim + 1] = R; 2560 coordsIn[0 * embedDim + 2] = -R; 2561 coordsIn[1 * embedDim + 0] = R; 2562 coordsIn[1 * embedDim + 1] = R; 2563 coordsIn[1 * embedDim + 2] = -R; 2564 coordsIn[2 * embedDim + 0] = R; 2565 coordsIn[2 * embedDim + 1] = -R; 2566 coordsIn[2 * embedDim + 2] = -R; 2567 coordsIn[3 * embedDim + 0] = -R; 2568 coordsIn[3 * embedDim + 1] = -R; 2569 coordsIn[3 * embedDim + 2] = -R; 2570 coordsIn[4 * embedDim + 0] = -R; 2571 coordsIn[4 * embedDim + 1] = R; 2572 coordsIn[4 * embedDim + 2] = R; 2573 coordsIn[5 * embedDim + 0] = R; 2574 coordsIn[5 * embedDim + 1] = R; 2575 coordsIn[5 * embedDim + 2] = R; 2576 coordsIn[6 * embedDim + 0] = -R; 2577 coordsIn[6 * embedDim + 1] = -R; 2578 coordsIn[6 * embedDim + 2] = R; 2579 coordsIn[7 * embedDim + 0] = R; 2580 coordsIn[7 * embedDim + 1] = -R; 2581 coordsIn[7 * embedDim + 2] = R; 2582 } 2583 } 2584 break; 2585 case 3: 2586 if (simplex) { 2587 const PetscReal edgeLen = 1.0 / PETSC_PHI; 2588 PetscReal vertexA[4] = {0.5, 0.5, 0.5, 0.5}; 2589 PetscReal vertexB[4] = {1.0, 0.0, 0.0, 0.0}; 2590 PetscReal vertexC[4] = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0}; 2591 const PetscInt degree = 12; 2592 PetscInt s[4] = {1, 1, 1}; 2593 PetscInt evenPerm[12][4] = { 2594 {0, 1, 2, 3}, 2595 {0, 2, 3, 1}, 2596 {0, 3, 1, 2}, 2597 {1, 0, 3, 2}, 2598 {1, 2, 0, 3}, 2599 {1, 3, 2, 0}, 2600 {2, 0, 1, 3}, 2601 {2, 1, 3, 0}, 2602 {2, 3, 0, 1}, 2603 {3, 0, 2, 1}, 2604 {3, 1, 0, 2}, 2605 {3, 2, 1, 0} 2606 }; 2607 PetscInt cone[4]; 2608 PetscInt *graph, p, i, j, k, l; 2609 2610 vertexA[0] *= R; 2611 vertexA[1] *= R; 2612 vertexA[2] *= R; 2613 vertexA[3] *= R; 2614 vertexB[0] *= R; 2615 vertexB[1] *= R; 2616 vertexB[2] *= R; 2617 vertexB[3] *= R; 2618 vertexC[0] *= R; 2619 vertexC[1] *= R; 2620 vertexC[2] *= R; 2621 vertexC[3] *= R; 2622 numCells = rank == 0 ? 600 : 0; 2623 numVerts = rank == 0 ? 120 : 0; 2624 firstVertex = numCells; 2625 /* Use the 600-cell, which for a unit sphere has coordinates which are 2626 2627 1/2 (\pm 1, \pm 1, \pm 1, \pm 1) 16 2628 (\pm 1, 0, 0, 0) all cyclic permutations 8 2629 1/2 (\pm 1, \pm phi, \pm 1/phi, 0) all even permutations 96 2630 2631 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 2632 length is then given by 1/\phi = 0.61803. 2633 2634 http://buzzard.pugetsound.edu/sage-practice/ch03s03.html 2635 http://mathworld.wolfram.com/600-Cell.html 2636 */ 2637 /* Construct vertices */ 2638 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2639 i = 0; 2640 if (rank == 0) { 2641 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2642 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2643 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2644 for (s[3] = -1; s[3] < 2; s[3] += 2) { 2645 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d]; 2646 ++i; 2647 } 2648 } 2649 } 2650 } 2651 for (p = 0; p < embedDim; ++p) { 2652 s[1] = s[2] = s[3] = 1; 2653 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2654 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim]; 2655 ++i; 2656 } 2657 } 2658 for (p = 0; p < 12; ++p) { 2659 s[3] = 1; 2660 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2661 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2662 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2663 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]]; 2664 ++i; 2665 } 2666 } 2667 } 2668 } 2669 } 2670 PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts); 2671 /* Construct graph */ 2672 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 2673 for (i = 0; i < numVerts; ++i) { 2674 for (j = 0, k = 0; j < numVerts; ++j) { 2675 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 2676 graph[i * numVerts + j] = 1; 2677 ++k; 2678 } 2679 } 2680 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 2681 } 2682 /* Build Topology */ 2683 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2684 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2685 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2686 /* Cells */ 2687 if (rank == 0) { 2688 for (i = 0, c = 0; i < numVerts; ++i) { 2689 for (j = 0; j < i; ++j) { 2690 for (k = 0; k < j; ++k) { 2691 for (l = 0; l < k; ++l) { 2692 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]) { 2693 cone[0] = firstVertex + i; 2694 cone[1] = firstVertex + j; 2695 cone[2] = firstVertex + k; 2696 cone[3] = firstVertex + l; 2697 /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */ 2698 { 2699 const PetscInt epsilon[4][4][4][4] = { 2700 {{{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}}}, 2701 2702 {{{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}}}, 2703 2704 {{{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}}}, 2705 2706 {{{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}} } 2707 }; 2708 PetscReal normal[4]; 2709 PetscInt e, f, g; 2710 2711 for (d = 0; d < embedDim; ++d) { 2712 normal[d] = 0.0; 2713 for (e = 0; e < embedDim; ++e) { 2714 for (f = 0; f < embedDim; ++f) { 2715 for (g = 0; g < embedDim; ++g) { 2716 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]); 2717 } 2718 } 2719 } 2720 } 2721 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 2722 PetscInt tmp = cone[1]; 2723 cone[1] = cone[2]; 2724 cone[2] = tmp; 2725 } 2726 } 2727 PetscCall(DMPlexSetCone(dm, c++, cone)); 2728 } 2729 } 2730 } 2731 } 2732 } 2733 } 2734 PetscCall(DMPlexSymmetrize(dm)); 2735 PetscCall(DMPlexStratify(dm)); 2736 PetscCall(PetscFree(graph)); 2737 } 2738 break; 2739 default: 2740 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim); 2741 } 2742 /* Create coordinates */ 2743 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2744 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2745 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim)); 2746 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts)); 2747 for (v = firstVertex; v < firstVertex + numVerts; ++v) { 2748 PetscCall(PetscSectionSetDof(coordSection, v, embedDim)); 2749 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim)); 2750 } 2751 PetscCall(PetscSectionSetUp(coordSection)); 2752 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2753 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2754 PetscCall(VecSetBlockSize(coordinates, embedDim)); 2755 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2756 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2757 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2758 PetscCall(VecGetArray(coordinates, &coords)); 2759 for (v = 0; v < numVerts; ++v) 2760 for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d]; 2761 PetscCall(VecRestoreArray(coordinates, &coords)); 2762 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2763 PetscCall(VecDestroy(&coordinates)); 2764 PetscCall(PetscFree(coordsIn)); 2765 { 2766 DM cdm; 2767 PetscDS cds; 2768 PetscScalar c = R; 2769 2770 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, snapToSphere)); 2771 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2772 PetscCall(DMGetDS(cdm, &cds)); 2773 PetscCall(PetscDSSetConstants(cds, 1, &c)); 2774 } 2775 /* Wait for coordinate creation before doing in-place modification */ 2776 if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2777 PetscFunctionReturn(0); 2778 } 2779 2780 typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]); 2781 2782 /* 2783 The Schwarz P implicit surface is 2784 2785 f(x) = cos(x0) + cos(x1) + cos(x2) = 0 2786 */ 2787 static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 2788 { 2789 PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)}; 2790 PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)}; 2791 f[0] = c[0] + c[1] + c[2]; 2792 for (PetscInt i = 0; i < 3; i++) { 2793 grad[i] = PETSC_PI * g[i]; 2794 for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.; 2795 } 2796 } 2797 2798 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 2799 static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 2800 { 2801 for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI); 2802 return 0; 2803 } 2804 2805 /* 2806 The Gyroid implicit surface is 2807 2808 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) 2809 2810 */ 2811 static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 2812 { 2813 PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))}; 2814 PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))}; 2815 f[0] = s[0] * c[1] + s[1] * c[2] + s[2] * c[0]; 2816 grad[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 2817 grad[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 2818 grad[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 2819 hess[0][0] = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]); 2820 hess[0][1] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 2821 hess[0][2] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 2822 hess[1][0] = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]); 2823 hess[1][1] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 2824 hess[2][2] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 2825 hess[2][0] = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]); 2826 hess[2][1] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 2827 hess[2][2] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 2828 } 2829 2830 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 2831 static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 2832 { 2833 PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))}; 2834 PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))}; 2835 u[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 2836 u[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 2837 u[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 2838 return 0; 2839 } 2840 2841 /* 2842 We wish to solve 2843 2844 min_y || y - x ||^2 subject to f(y) = 0 2845 2846 Let g(y) = grad(f). The minimization problem is equivalent to asking to satisfy 2847 f(y) = 0 and (y-x) is parallel to g(y). We do this by using Householder QR to obtain a basis for the 2848 tangent space and ask for both components in the tangent space to be zero. 2849 2850 Take g to be a column vector and compute the "full QR" factorization Q R = g, 2851 where Q = I - 2 n n^T is a symmetric orthogonal matrix. 2852 The first column of Q is parallel to g so the remaining two columns span the null space. 2853 Let Qn = Q[:,1:] be those remaining columns. Then Qn Qn^T is an orthogonal projector into the tangent space. 2854 Since Q is symmetric, this is equivalent to multipyling by Q and taking the last two entries. 2855 In total, we have a system of 3 equations in 3 unknowns: 2856 2857 f(y) = 0 1 equation 2858 Qn^T (y - x) = 0 2 equations 2859 2860 Here, we compute the residual and Jacobian of this system. 2861 */ 2862 static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[]) 2863 { 2864 PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])}; 2865 PetscReal d[3] = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])}; 2866 PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign; 2867 PetscReal n_y[3][3] = { 2868 {0, 0, 0}, 2869 {0, 0, 0}, 2870 {0, 0, 0} 2871 }; 2872 2873 feval(yreal, &f, grad, n_y); 2874 2875 for (PetscInt i = 0; i < 3; i++) n[i] = grad[i]; 2876 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 2877 for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i]; 2878 2879 // Define the Householder reflector 2880 sign = n[0] >= 0 ? 1. : -1.; 2881 n[0] += norm * sign; 2882 for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign; 2883 2884 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 2885 norm_y[0] = 1. / norm * (n[0] * n_y[0][0]); 2886 norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]); 2887 norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]); 2888 2889 for (PetscInt i = 0; i < 3; i++) { 2890 n[i] /= norm; 2891 for (PetscInt j = 0; j < 3; j++) { 2892 // note that n[i] is n_old[i]/norm when executing the code below 2893 n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j]; 2894 } 2895 } 2896 2897 nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2]; 2898 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]; 2899 2900 res[0] = f; 2901 res[1] = d[1] - 2 * n[1] * nd; 2902 res[2] = d[2] - 2 * n[2] * nd; 2903 // J[j][i] is J_{ij} (column major) 2904 for (PetscInt j = 0; j < 3; j++) { 2905 J[0 + j * 3] = grad[j]; 2906 J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]); 2907 J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]); 2908 } 2909 } 2910 2911 /* 2912 Project x to the nearest point on the implicit surface using Newton's method. 2913 */ 2914 static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[]) 2915 { 2916 PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess 2917 2918 PetscFunctionBegin; 2919 for (PetscInt iter = 0; iter < 10; iter++) { 2920 PetscScalar res[3], J[9]; 2921 PetscReal resnorm; 2922 TPSNearestPointResJac(feval, x, y, res, J); 2923 resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2]))); 2924 if (0) { // Turn on this monitor if you need to confirm quadratic convergence 2925 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]))); 2926 } 2927 if (resnorm < PETSC_SMALL) break; 2928 2929 // Take the Newton step 2930 PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL)); 2931 PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res); 2932 } 2933 for (PetscInt i = 0; i < 3; i++) x[i] = y[i]; 2934 PetscFunctionReturn(0); 2935 } 2936 2937 const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL}; 2938 2939 static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness) 2940 { 2941 PetscMPIInt rank; 2942 PetscInt topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0; 2943 PetscInt(*edges)[2] = NULL, *edgeSets = NULL; 2944 PetscInt *cells_flat = NULL; 2945 PetscReal *vtxCoords = NULL; 2946 TPSEvaluateFunc evalFunc = NULL; 2947 PetscSimplePointFunc normalFunc = NULL; 2948 DMLabel label; 2949 2950 PetscFunctionBegin; 2951 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2952 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); 2953 switch (tpstype) { 2954 case DMPLEX_TPS_SCHWARZ_P: 2955 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"); 2956 if (rank == 0) { 2957 PetscInt(*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn] 2958 PetscInt Njunctions = 0, Ncuts = 0, Npipes[3], vcount; 2959 PetscReal L = 1; 2960 2961 Npipes[0] = (extent[0] + 1) * extent[1] * extent[2]; 2962 Npipes[1] = extent[0] * (extent[1] + 1) * extent[2]; 2963 Npipes[2] = extent[0] * extent[1] * (extent[2] + 1); 2964 Njunctions = extent[0] * extent[1] * extent[2]; 2965 Ncuts = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]); 2966 numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions; 2967 PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords)); 2968 PetscCall(PetscMalloc1(Njunctions, &cells)); 2969 PetscCall(PetscMalloc1(Ncuts * 4, &edges)); 2970 PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets)); 2971 // x-normal pipes 2972 vcount = 0; 2973 for (PetscInt i = 0; i < extent[0] + 1; i++) { 2974 for (PetscInt j = 0; j < extent[1]; j++) { 2975 for (PetscInt k = 0; k < extent[2]; k++) { 2976 for (PetscInt l = 0; l < 4; l++) { 2977 vtxCoords[vcount++] = (2 * i - 1) * L; 2978 vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 2979 vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 2980 } 2981 } 2982 } 2983 } 2984 // y-normal pipes 2985 for (PetscInt i = 0; i < extent[0]; i++) { 2986 for (PetscInt j = 0; j < extent[1] + 1; j++) { 2987 for (PetscInt k = 0; k < extent[2]; k++) { 2988 for (PetscInt l = 0; l < 4; l++) { 2989 vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 2990 vtxCoords[vcount++] = (2 * j - 1) * L; 2991 vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 2992 } 2993 } 2994 } 2995 } 2996 // z-normal pipes 2997 for (PetscInt i = 0; i < extent[0]; i++) { 2998 for (PetscInt j = 0; j < extent[1]; j++) { 2999 for (PetscInt k = 0; k < extent[2] + 1; k++) { 3000 for (PetscInt l = 0; l < 4; l++) { 3001 vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3002 vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3003 vtxCoords[vcount++] = (2 * k - 1) * L; 3004 } 3005 } 3006 } 3007 } 3008 // junctions 3009 for (PetscInt i = 0; i < extent[0]; i++) { 3010 for (PetscInt j = 0; j < extent[1]; j++) { 3011 for (PetscInt k = 0; k < extent[2]; k++) { 3012 const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8; 3013 PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count"); 3014 for (PetscInt ii = 0; ii < 2; ii++) { 3015 for (PetscInt jj = 0; jj < 2; jj++) { 3016 for (PetscInt kk = 0; kk < 2; kk++) { 3017 double Ls = (1 - sqrt(2) / 4) * L; 3018 vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls; 3019 vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls; 3020 vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls; 3021 } 3022 } 3023 } 3024 const PetscInt jfaces[3][2][4] = { 3025 {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned 3026 {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned 3027 {{6, 2, 0, 4}, {7, 3, 1, 5}} // z-aligned 3028 }; 3029 const PetscInt pipe_lo[3] = {// vertex numbers of pipes 3030 ((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}; 3031 const PetscInt pipe_hi[3] = {// vertex numbers of pipes 3032 (((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}; 3033 for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z 3034 const PetscInt ijk[3] = {i, j, k}; 3035 for (PetscInt l = 0; l < 4; l++) { // rotations 3036 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l; 3037 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l]; 3038 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4]; 3039 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4; 3040 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l]; 3041 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l; 3042 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4; 3043 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4]; 3044 if (ijk[dir] == 0) { 3045 edges[numEdges][0] = pipe_lo[dir] + l; 3046 edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4; 3047 edgeSets[numEdges] = dir * 2 + 1; 3048 numEdges++; 3049 } 3050 if (ijk[dir] + 1 == extent[dir]) { 3051 edges[numEdges][0] = pipe_hi[dir] + l; 3052 edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4; 3053 edgeSets[numEdges] = dir * 2 + 2; 3054 numEdges++; 3055 } 3056 } 3057 } 3058 } 3059 } 3060 } 3061 PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts); 3062 numFaces = 24 * Njunctions; 3063 cells_flat = cells[0][0][0]; 3064 } 3065 evalFunc = TPSEvaluate_SchwarzP; 3066 normalFunc = TPSExtrudeNormalFunc_SchwarzP; 3067 break; 3068 case DMPLEX_TPS_GYROID: 3069 if (rank == 0) { 3070 // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set 3071 // 3072 // 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) 3073 // 3074 // on the cell [0,2]^3. 3075 // 3076 // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2]. 3077 // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins 3078 // like a boomerang: 3079 // 3080 // z = 0 z = 1/4 z = 1/2 z = 3/4 // 3081 // ----- ------- ------- ------- // 3082 // // 3083 // + + + + + + + \ + // 3084 // \ / \ // 3085 // \ `-_ _-' / } // 3086 // *-_ `-' _-' / // 3087 // + `-+ + + +-' + + / + // 3088 // // 3089 // // 3090 // z = 1 z = 5/4 z = 3/2 z = 7/4 // 3091 // ----- ------- ------- ------- // 3092 // // 3093 // +-_ + + + + _-+ + / + // 3094 // `-_ _-_ _-` / // 3095 // \ _-' `-_ / { // 3096 // \ / \ // 3097 // + + + + + + + \ + // 3098 // 3099 // 3100 // This course mesh approximates each of these slices by two line segments, 3101 // and then connects the segments in consecutive layers with quadrilateral faces. 3102 // All of the end points of the segments are multiples of 1/4 except for the 3103 // point * in the picture for z = 0 above and the similar points in other layers. 3104 // That point is at (gamma, gamma, 0), where gamma is calculated below. 3105 // 3106 // The column [1,2]x[1,2]x[0,2] looks the same as this column; 3107 // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images. 3108 // 3109 // As for how this method turned into the names given to the vertices: 3110 // that was not systematic, it was just the way it worked out in my handwritten notes. 3111 3112 PetscInt facesPerBlock = 64; 3113 PetscInt vertsPerBlock = 56; 3114 PetscInt extentPlus[3]; 3115 PetscInt numBlocks, numBlocksPlus; 3116 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; 3117 const PetscInt pattern[64][4] = { 3118 /* face to vertex within the coarse discretization of a single gyroid block */ 3119 /* layer 0 */ 3120 {A, C, K, G }, 3121 {C, B, II, K }, 3122 {D, A, H, L }, 3123 {B + 56 * 1, D, L, J }, 3124 {E, B + 56 * 1, J, N }, 3125 {A + 56 * 2, E, N, H + 56 * 2 }, 3126 {F, A + 56 * 2, G + 56 * 2, M }, 3127 {B, F, M, II }, 3128 /* layer 1 */ 3129 {G, K, Q, O }, 3130 {K, II, P, Q }, 3131 {L, H, O + 56 * 1, R }, 3132 {J, L, R, P }, 3133 {N, J, P, S }, 3134 {H + 56 * 2, N, S, O + 56 * 3 }, 3135 {M, G + 56 * 2, O + 56 * 2, T }, 3136 {II, M, T, P }, 3137 /* layer 2 */ 3138 {O, Q, Y, U }, 3139 {Q, P, W, Y }, 3140 {R, O + 56 * 1, U + 56 * 1, Ap }, 3141 {P, R, Ap, W }, 3142 {S, P, X, Bp }, 3143 {O + 56 * 3, S, Bp, V + 56 * 1 }, 3144 {T, O + 56 * 2, V, Z }, 3145 {P, T, Z, X }, 3146 /* layer 3 */ 3147 {U, Y, Ep, Dp }, 3148 {Y, W, Cp, Ep }, 3149 {Ap, U + 56 * 1, Dp + 56 * 1, Gp }, 3150 {W, Ap, Gp, Cp }, 3151 {Bp, X, Cp + 56 * 2, Fp }, 3152 {V + 56 * 1, Bp, Fp, Dp + 56 * 1}, 3153 {Z, V, Dp, Hp }, 3154 {X, Z, Hp, Cp + 56 * 2}, 3155 /* layer 4 */ 3156 {Dp, Ep, Mp, Kp }, 3157 {Ep, Cp, Ip, Mp }, 3158 {Gp, Dp + 56 * 1, Lp, Np }, 3159 {Cp, Gp, Np, Jp }, 3160 {Fp, Cp + 56 * 2, Jp + 56 * 2, Pp }, 3161 {Dp + 56 * 1, Fp, Pp, Lp }, 3162 {Hp, Dp, Kp, Op }, 3163 {Cp + 56 * 2, Hp, Op, Ip + 56 * 2}, 3164 /* layer 5 */ 3165 {Kp, Mp, Sp, Rp }, 3166 {Mp, Ip, Qp, Sp }, 3167 {Np, Lp, Rp, Tp }, 3168 {Jp, Np, Tp, Qp + 56 * 1}, 3169 {Pp, Jp + 56 * 2, Qp + 56 * 3, Up }, 3170 {Lp, Pp, Up, Rp }, 3171 {Op, Kp, Rp, Vp }, 3172 {Ip + 56 * 2, Op, Vp, Qp + 56 * 2}, 3173 /* layer 6 */ 3174 {Rp, Sp, Aq, Yp }, 3175 {Sp, Qp, Wp, Aq }, 3176 {Tp, Rp, Yp, Cq }, 3177 {Qp + 56 * 1, Tp, Cq, Wp + 56 * 1}, 3178 {Up, Qp + 56 * 3, Xp + 56 * 1, Dq }, 3179 {Rp, Up, Dq, Zp }, 3180 {Vp, Rp, Zp, Bq }, 3181 {Qp + 56 * 2, Vp, Bq, Xp }, 3182 /* layer 7 (the top is the periodic image of the bottom of layer 0) */ 3183 {Yp, Aq, C + 56 * 4, A + 56 * 4 }, 3184 {Aq, Wp, B + 56 * 4, C + 56 * 4 }, 3185 {Cq, Yp, A + 56 * 4, D + 56 * 4 }, 3186 {Wp + 56 * 1, Cq, D + 56 * 4, B + 56 * 5 }, 3187 {Dq, Xp + 56 * 1, B + 56 * 5, E + 56 * 4 }, 3188 {Zp, Dq, E + 56 * 4, A + 56 * 6 }, 3189 {Bq, Zp, A + 56 * 6, F + 56 * 4 }, 3190 {Xp, Bq, F + 56 * 4, B + 56 * 4 } 3191 }; 3192 const PetscReal gamma = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI; 3193 const PetscReal patternCoords[56][3] = { 3194 {1., 0., 0. }, /* A */ 3195 {0., 1., 0. }, /* B */ 3196 {gamma, gamma, 0. }, /* C */ 3197 {1 + gamma, 1 - gamma, 0. }, /* D */ 3198 {2 - gamma, 2 - gamma, 0. }, /* E */ 3199 {1 - gamma, 1 + gamma, 0. }, /* F */ 3200 3201 {.5, 0, .25 }, /* G */ 3202 {1.5, 0., .25 }, /* H */ 3203 {.5, 1., .25 }, /* II */ 3204 {1.5, 1., .25 }, /* J */ 3205 {.25, .5, .25 }, /* K */ 3206 {1.25, .5, .25 }, /* L */ 3207 {.75, 1.5, .25 }, /* M */ 3208 {1.75, 1.5, .25 }, /* N */ 3209 3210 {0., 0., .5 }, /* O */ 3211 {1., 1., .5 }, /* P */ 3212 {gamma, 1 - gamma, .5 }, /* Q */ 3213 {1 + gamma, gamma, .5 }, /* R */ 3214 {2 - gamma, 1 + gamma, .5 }, /* S */ 3215 {1 - gamma, 2 - gamma, .5 }, /* T */ 3216 3217 {0., .5, .75 }, /* U */ 3218 {0., 1.5, .75 }, /* V */ 3219 {1., .5, .75 }, /* W */ 3220 {1., 1.5, .75 }, /* X */ 3221 {.5, .75, .75 }, /* Y */ 3222 {.5, 1.75, .75 }, /* Z */ 3223 {1.5, .25, .75 }, /* Ap */ 3224 {1.5, 1.25, .75 }, /* Bp */ 3225 3226 {1., 0., 1. }, /* Cp */ 3227 {0., 1., 1. }, /* Dp */ 3228 {1 - gamma, 1 - gamma, 1. }, /* Ep */ 3229 {1 + gamma, 1 + gamma, 1. }, /* Fp */ 3230 {2 - gamma, gamma, 1. }, /* Gp */ 3231 {gamma, 2 - gamma, 1. }, /* Hp */ 3232 3233 {.5, 0., 1.25}, /* Ip */ 3234 {1.5, 0., 1.25}, /* Jp */ 3235 {.5, 1., 1.25}, /* Kp */ 3236 {1.5, 1., 1.25}, /* Lp */ 3237 {.75, .5, 1.25}, /* Mp */ 3238 {1.75, .5, 1.25}, /* Np */ 3239 {.25, 1.5, 1.25}, /* Op */ 3240 {1.25, 1.5, 1.25}, /* Pp */ 3241 3242 {0., 0., 1.5 }, /* Qp */ 3243 {1., 1., 1.5 }, /* Rp */ 3244 {1 - gamma, gamma, 1.5 }, /* Sp */ 3245 {2 - gamma, 1 - gamma, 1.5 }, /* Tp */ 3246 {1 + gamma, 2 - gamma, 1.5 }, /* Up */ 3247 {gamma, 1 + gamma, 1.5 }, /* Vp */ 3248 3249 {0., .5, 1.75}, /* Wp */ 3250 {0., 1.5, 1.75}, /* Xp */ 3251 {1., .5, 1.75}, /* Yp */ 3252 {1., 1.5, 1.75}, /* Zp */ 3253 {.5, .25, 1.75}, /* Aq */ 3254 {.5, 1.25, 1.75}, /* Bq */ 3255 {1.5, .75, 1.75}, /* Cq */ 3256 {1.5, 1.75, 1.75}, /* Dq */ 3257 }; 3258 PetscInt(*cells)[64][4] = NULL; 3259 PetscBool *seen; 3260 PetscInt *vertToTrueVert; 3261 PetscInt count; 3262 3263 for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1; 3264 numBlocks = 1; 3265 for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i]; 3266 numBlocksPlus = 1; 3267 for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i]; 3268 numFaces = numBlocks * facesPerBlock; 3269 PetscCall(PetscMalloc1(numBlocks, &cells)); 3270 PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen)); 3271 for (PetscInt k = 0; k < extent[2]; k++) { 3272 for (PetscInt j = 0; j < extent[1]; j++) { 3273 for (PetscInt i = 0; i < extent[0]; i++) { 3274 for (PetscInt f = 0; f < facesPerBlock; f++) { 3275 for (PetscInt v = 0; v < 4; v++) { 3276 PetscInt vertRaw = pattern[f][v]; 3277 PetscInt blockidx = vertRaw / 56; 3278 PetscInt patternvert = vertRaw % 56; 3279 PetscInt xplus = (blockidx & 1); 3280 PetscInt yplus = (blockidx & 2) >> 1; 3281 PetscInt zplus = (blockidx & 4) >> 2; 3282 PetscInt zcoord = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus); 3283 PetscInt ycoord = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus); 3284 PetscInt xcoord = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus); 3285 PetscInt vert = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert; 3286 3287 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert; 3288 seen[vert] = PETSC_TRUE; 3289 } 3290 } 3291 } 3292 } 3293 } 3294 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) 3295 if (seen[i]) numVertices++; 3296 count = 0; 3297 PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert)); 3298 PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords)); 3299 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1; 3300 for (PetscInt k = 0; k < extentPlus[2]; k++) { 3301 for (PetscInt j = 0; j < extentPlus[1]; j++) { 3302 for (PetscInt i = 0; i < extentPlus[0]; i++) { 3303 for (PetscInt v = 0; v < vertsPerBlock; v++) { 3304 PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v; 3305 3306 if (seen[vIdx]) { 3307 PetscInt thisVert; 3308 3309 vertToTrueVert[vIdx] = thisVert = count++; 3310 3311 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d]; 3312 vtxCoords[3 * thisVert + 0] += i * 2; 3313 vtxCoords[3 * thisVert + 1] += j * 2; 3314 vtxCoords[3 * thisVert + 2] += k * 2; 3315 } 3316 } 3317 } 3318 } 3319 } 3320 for (PetscInt i = 0; i < numBlocks; i++) { 3321 for (PetscInt f = 0; f < facesPerBlock; f++) { 3322 for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]]; 3323 } 3324 } 3325 PetscCall(PetscFree(vertToTrueVert)); 3326 PetscCall(PetscFree(seen)); 3327 cells_flat = cells[0][0]; 3328 numEdges = 0; 3329 for (PetscInt i = 0; i < numFaces; i++) { 3330 for (PetscInt e = 0; e < 4; e++) { 3331 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 3332 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 3333 3334 for (PetscInt d = 0; d < 3; d++) { 3335 if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) { 3336 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++; 3337 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++; 3338 } 3339 } 3340 } 3341 } 3342 PetscCall(PetscMalloc1(numEdges, &edges)); 3343 PetscCall(PetscMalloc1(numEdges, &edgeSets)); 3344 for (PetscInt edge = 0, i = 0; i < numFaces; i++) { 3345 for (PetscInt e = 0; e < 4; e++) { 3346 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 3347 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 3348 3349 for (PetscInt d = 0; d < 3; d++) { 3350 if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) { 3351 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) { 3352 edges[edge][0] = ev[0]; 3353 edges[edge][1] = ev[1]; 3354 edgeSets[edge++] = 2 * d; 3355 } 3356 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) { 3357 edges[edge][0] = ev[0]; 3358 edges[edge][1] = ev[1]; 3359 edgeSets[edge++] = 2 * d + 1; 3360 } 3361 } 3362 } 3363 } 3364 } 3365 } 3366 evalFunc = TPSEvaluate_Gyroid; 3367 normalFunc = TPSExtrudeNormalFunc_Gyroid; 3368 break; 3369 } 3370 3371 PetscCall(DMSetDimension(dm, topoDim)); 3372 if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat)); 3373 else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL)); 3374 PetscCall(PetscFree(cells_flat)); 3375 { 3376 DM idm; 3377 PetscCall(DMPlexInterpolate(dm, &idm)); 3378 PetscCall(DMPlexReplace_Internal(dm, &idm)); 3379 } 3380 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords)); 3381 else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL)); 3382 PetscCall(PetscFree(vtxCoords)); 3383 3384 PetscCall(DMCreateLabel(dm, "Face Sets")); 3385 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 3386 for (PetscInt e = 0; e < numEdges; e++) { 3387 PetscInt njoin; 3388 const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]}; 3389 PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join)); 3390 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]); 3391 PetscCall(DMLabelSetValue(label, join[0], edgeSets[e])); 3392 PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join)); 3393 } 3394 PetscCall(PetscFree(edges)); 3395 PetscCall(PetscFree(edgeSets)); 3396 if (tps_distribute) { 3397 DM pdm = NULL; 3398 PetscPartitioner part; 3399 3400 PetscCall(DMPlexGetPartitioner(dm, &part)); 3401 PetscCall(PetscPartitionerSetFromOptions(part)); 3402 PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm)); 3403 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 3404 // Do not auto-distribute again 3405 PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE)); 3406 } 3407 3408 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 3409 for (PetscInt refine = 0; refine < refinements; refine++) { 3410 PetscInt m; 3411 DM dmf; 3412 Vec X; 3413 PetscScalar *x; 3414 PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf)); 3415 PetscCall(DMPlexReplace_Internal(dm, &dmf)); 3416 3417 PetscCall(DMGetCoordinatesLocal(dm, &X)); 3418 PetscCall(VecGetLocalSize(X, &m)); 3419 PetscCall(VecGetArray(X, &x)); 3420 for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i])); 3421 PetscCall(VecRestoreArray(X, &x)); 3422 } 3423 3424 // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices. 3425 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 3426 PetscCall(DMPlexLabelComplete(dm, label)); 3427 3428 if (thickness > 0) { 3429 DM edm, cdm, ecdm; 3430 DMPlexTransform tr; 3431 const char *prefix; 3432 PetscOptions options; 3433 // Code from DMPlexExtrude 3434 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 3435 PetscCall(DMPlexTransformSetDM(tr, dm)); 3436 PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDE)); 3437 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 3438 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 3439 PetscCall(PetscObjectGetOptions((PetscObject)dm, &options)); 3440 PetscCall(PetscObjectSetOptions((PetscObject)tr, options)); 3441 PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers)); 3442 PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness)); 3443 PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE)); 3444 PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE)); 3445 PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc)); 3446 PetscCall(DMPlexTransformSetFromOptions(tr)); 3447 PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL)); 3448 PetscCall(DMPlexTransformSetUp(tr)); 3449 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view")); 3450 PetscCall(DMPlexTransformApply(tr, dm, &edm)); 3451 PetscCall(DMCopyDisc(dm, edm)); 3452 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3453 PetscCall(DMGetCoordinateDM(edm, &ecdm)); 3454 PetscCall(DMCopyDisc(cdm, ecdm)); 3455 PetscCall(DMPlexTransformCreateDiscLabels(tr, edm)); 3456 PetscCall(DMPlexTransformDestroy(&tr)); 3457 if (edm) { 3458 ((DM_Plex *)edm->data)->printFEM = ((DM_Plex *)dm->data)->printFEM; 3459 ((DM_Plex *)edm->data)->printL2 = ((DM_Plex *)dm->data)->printL2; 3460 ((DM_Plex *)edm->data)->printLocate = ((DM_Plex *)dm->data)->printLocate; 3461 } 3462 PetscCall(DMPlexReplace_Internal(dm, &edm)); 3463 } 3464 PetscFunctionReturn(0); 3465 } 3466 3467 /*@ 3468 DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface 3469 3470 Collective 3471 3472 Input Parameters: 3473 + comm - The communicator for the `DM` object 3474 . tpstype - Type of triply-periodic surface 3475 . extent - Array of length 3 containing number of periods in each direction 3476 . periodic - array of length 3 with periodicity, or NULL for non-periodic 3477 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable) 3478 . refinements - Number of factor-of-2 refinements of 2D manifold mesh 3479 . layers - Number of cell layers extruded in normal direction 3480 - thickness - Thickness in normal direction 3481 3482 Output Parameter: 3483 . dm - The `DM` object 3484 3485 Level: beginner 3486 3487 Notes: 3488 This meshes the surface of the Schwarz P or Gyroid surfaces. Schwarz P is is the simplest member of the triply-periodic minimal surfaces. 3489 https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22) and can be cut with "clean" boundaries. 3490 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. 3491 Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested. 3492 On each refinement, all vertices are projected to their nearest point on the surface. 3493 This projection could readily be extended to related surfaces. 3494 3495 The face (edge) sets for the Schwarz P surface are numbered 1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z). 3496 When the mesh is refined, "Face Sets" contain the new vertices (created during refinement). Use DMPlexLabelComplete() to propagate to coarse-level vertices. 3497 3498 Developer Note: 3499 The Gyroid mesh does not currently mark boundary sets. 3500 3501 References: 3502 . * - Maskery et al, Insights into the mechanical properties of several triply periodic minimal surface lattice structures made by polymer additive manufacturing, 2017. 3503 https://doi.org/10.1016/j.polymer.2017.11.049 3504 3505 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()` 3506 @*/ 3507 PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm) 3508 { 3509 PetscFunctionBegin; 3510 PetscCall(DMCreate(comm, dm)); 3511 PetscCall(DMSetType(*dm, DMPLEX)); 3512 PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness)); 3513 PetscFunctionReturn(0); 3514 } 3515 3516 /*@ 3517 DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d. 3518 3519 Collective 3520 3521 Input Parameters: 3522 + comm - The communicator for the `DM` object 3523 . dim - The dimension 3524 . simplex - Use simplices, or tensor product cells 3525 - R - The radius 3526 3527 Output Parameter: 3528 . dm - The `DM` object 3529 3530 Level: beginner 3531 3532 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 3533 @*/ 3534 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm) 3535 { 3536 PetscFunctionBegin; 3537 PetscValidPointer(dm, 5); 3538 PetscCall(DMCreate(comm, dm)); 3539 PetscCall(DMSetType(*dm, DMPLEX)); 3540 PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R)); 3541 PetscFunctionReturn(0); 3542 } 3543 3544 static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R) 3545 { 3546 DM sdm, vol; 3547 DMLabel bdlabel; 3548 3549 PetscFunctionBegin; 3550 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm)); 3551 PetscCall(DMSetType(sdm, DMPLEX)); 3552 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sdm, "bd_")); 3553 PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R)); 3554 PetscCall(DMSetFromOptions(sdm)); 3555 PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view")); 3556 PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol)); 3557 PetscCall(DMDestroy(&sdm)); 3558 PetscCall(DMPlexReplace_Internal(dm, &vol)); 3559 PetscCall(DMCreateLabel(dm, "marker")); 3560 PetscCall(DMGetLabel(dm, "marker", &bdlabel)); 3561 PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel)); 3562 PetscCall(DMPlexLabelComplete(dm, bdlabel)); 3563 PetscFunctionReturn(0); 3564 } 3565 3566 /*@ 3567 DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d. 3568 3569 Collective 3570 3571 Input Parameters: 3572 + comm - The communicator for the `DM` object 3573 . dim - The dimension 3574 - R - The radius 3575 3576 Output Parameter: 3577 . dm - The `DM` object 3578 3579 Options Database Key: 3580 - bd_dm_refine - This will refine the surface mesh preserving the sphere geometry 3581 3582 Level: beginner 3583 3584 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 3585 @*/ 3586 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm) 3587 { 3588 PetscFunctionBegin; 3589 PetscCall(DMCreate(comm, dm)); 3590 PetscCall(DMSetType(*dm, DMPLEX)); 3591 PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R)); 3592 PetscFunctionReturn(0); 3593 } 3594 3595 static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct) 3596 { 3597 PetscFunctionBegin; 3598 switch (ct) { 3599 case DM_POLYTOPE_POINT: { 3600 PetscInt numPoints[1] = {1}; 3601 PetscInt coneSize[1] = {0}; 3602 PetscInt cones[1] = {0}; 3603 PetscInt coneOrientations[1] = {0}; 3604 PetscScalar vertexCoords[1] = {0.0}; 3605 3606 PetscCall(DMSetDimension(rdm, 0)); 3607 PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3608 } break; 3609 case DM_POLYTOPE_SEGMENT: { 3610 PetscInt numPoints[2] = {2, 1}; 3611 PetscInt coneSize[3] = {2, 0, 0}; 3612 PetscInt cones[2] = {1, 2}; 3613 PetscInt coneOrientations[2] = {0, 0}; 3614 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 3615 3616 PetscCall(DMSetDimension(rdm, 1)); 3617 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3618 } break; 3619 case DM_POLYTOPE_POINT_PRISM_TENSOR: { 3620 PetscInt numPoints[2] = {2, 1}; 3621 PetscInt coneSize[3] = {2, 0, 0}; 3622 PetscInt cones[2] = {1, 2}; 3623 PetscInt coneOrientations[2] = {0, 0}; 3624 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 3625 3626 PetscCall(DMSetDimension(rdm, 1)); 3627 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3628 } break; 3629 case DM_POLYTOPE_TRIANGLE: { 3630 PetscInt numPoints[2] = {3, 1}; 3631 PetscInt coneSize[4] = {3, 0, 0, 0}; 3632 PetscInt cones[3] = {1, 2, 3}; 3633 PetscInt coneOrientations[3] = {0, 0, 0}; 3634 PetscScalar vertexCoords[6] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0}; 3635 3636 PetscCall(DMSetDimension(rdm, 2)); 3637 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3638 } break; 3639 case DM_POLYTOPE_QUADRILATERAL: { 3640 PetscInt numPoints[2] = {4, 1}; 3641 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 3642 PetscInt cones[4] = {1, 2, 3, 4}; 3643 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 3644 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0}; 3645 3646 PetscCall(DMSetDimension(rdm, 2)); 3647 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3648 } break; 3649 case DM_POLYTOPE_SEG_PRISM_TENSOR: { 3650 PetscInt numPoints[2] = {4, 1}; 3651 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 3652 PetscInt cones[4] = {1, 2, 3, 4}; 3653 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 3654 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; 3655 3656 PetscCall(DMSetDimension(rdm, 2)); 3657 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3658 } break; 3659 case DM_POLYTOPE_TETRAHEDRON: { 3660 PetscInt numPoints[2] = {4, 1}; 3661 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 3662 PetscInt cones[4] = {1, 2, 3, 4}; 3663 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 3664 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}; 3665 3666 PetscCall(DMSetDimension(rdm, 3)); 3667 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3668 } break; 3669 case DM_POLYTOPE_HEXAHEDRON: { 3670 PetscInt numPoints[2] = {8, 1}; 3671 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 3672 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 3673 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 3674 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}; 3675 3676 PetscCall(DMSetDimension(rdm, 3)); 3677 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3678 } break; 3679 case DM_POLYTOPE_TRI_PRISM: { 3680 PetscInt numPoints[2] = {6, 1}; 3681 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 3682 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 3683 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 3684 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}; 3685 3686 PetscCall(DMSetDimension(rdm, 3)); 3687 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3688 } break; 3689 case DM_POLYTOPE_TRI_PRISM_TENSOR: { 3690 PetscInt numPoints[2] = {6, 1}; 3691 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 3692 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 3693 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 3694 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}; 3695 3696 PetscCall(DMSetDimension(rdm, 3)); 3697 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3698 } break; 3699 case DM_POLYTOPE_QUAD_PRISM_TENSOR: { 3700 PetscInt numPoints[2] = {8, 1}; 3701 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 3702 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 3703 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 3704 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}; 3705 3706 PetscCall(DMSetDimension(rdm, 3)); 3707 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3708 } break; 3709 case DM_POLYTOPE_PYRAMID: { 3710 PetscInt numPoints[2] = {5, 1}; 3711 PetscInt coneSize[6] = {5, 0, 0, 0, 0, 0}; 3712 PetscInt cones[5] = {1, 2, 3, 4, 5}; 3713 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 3714 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}; 3715 3716 PetscCall(DMSetDimension(rdm, 3)); 3717 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3718 } break; 3719 default: 3720 SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]); 3721 } 3722 { 3723 PetscInt Nv, v; 3724 3725 /* Must create the celltype label here so that we do not automatically try to compute the types */ 3726 PetscCall(DMCreateLabel(rdm, "celltype")); 3727 PetscCall(DMPlexSetCellType(rdm, 0, ct)); 3728 PetscCall(DMPlexGetChart(rdm, NULL, &Nv)); 3729 for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT)); 3730 } 3731 PetscCall(DMPlexInterpolateInPlace_Internal(rdm)); 3732 PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct])); 3733 PetscFunctionReturn(0); 3734 } 3735 3736 /*@ 3737 DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell 3738 3739 Collective 3740 3741 Input Parameters: 3742 + comm - The communicator 3743 - ct - The cell type of the reference cell 3744 3745 Output Parameter: 3746 . refdm - The reference cell 3747 3748 Level: intermediate 3749 3750 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateReferenceCell()`, `DMPlexCreateBoxMesh()` 3751 @*/ 3752 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm) 3753 { 3754 PetscFunctionBegin; 3755 PetscCall(DMCreate(comm, refdm)); 3756 PetscCall(DMSetType(*refdm, DMPLEX)); 3757 PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct)); 3758 PetscFunctionReturn(0); 3759 } 3760 3761 static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[]) 3762 { 3763 DM plex; 3764 DMLabel label; 3765 PetscBool hasLabel; 3766 3767 PetscFunctionBegin; 3768 PetscCall(DMHasLabel(dm, name, &hasLabel)); 3769 if (hasLabel) PetscFunctionReturn(0); 3770 PetscCall(DMCreateLabel(dm, name)); 3771 PetscCall(DMGetLabel(dm, name, &label)); 3772 PetscCall(DMConvert(dm, DMPLEX, &plex)); 3773 PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label)); 3774 PetscCall(DMPlexLabelComplete(plex, label)); 3775 PetscCall(DMDestroy(&plex)); 3776 PetscFunctionReturn(0); 3777 } 3778 3779 /* 3780 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. 3781 3782 (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0])) 3783 */ 3784 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[]) 3785 { 3786 const PetscReal low = PetscRealPart(constants[0]); 3787 const PetscReal upp = PetscRealPart(constants[1]); 3788 const PetscReal r = PetscRealPart(u[1]); 3789 const PetscReal th = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low); 3790 3791 f0[0] = r * PetscCosReal(th); 3792 f0[1] = r * PetscSinReal(th); 3793 } 3794 3795 const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "unknown", "DMPlexShape", "DM_SHAPE_", NULL}; 3796 3797 static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems *PetscOptionsObject, PetscBool *useCoordSpace, DM dm) 3798 { 3799 DMPlexShape shape = DM_SHAPE_BOX; 3800 DMPolytopeType cell = DM_POLYTOPE_TRIANGLE; 3801 PetscInt dim = 2; 3802 PetscBool simplex = PETSC_TRUE, interpolate = PETSC_TRUE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE; 3803 PetscBool flg, flg2, fflg, bdfflg, nameflg; 3804 MPI_Comm comm; 3805 char filename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 3806 char bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 3807 char plexname[PETSC_MAX_PATH_LEN] = ""; 3808 3809 PetscFunctionBegin; 3810 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3811 /* TODO Turn this into a registration interface */ 3812 PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg)); 3813 PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg)); 3814 PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg)); 3815 PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL)); 3816 PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL)); 3817 PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg)); 3818 PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0)); 3819 PetscCheck(dim >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " should be in [0, infinity)", dim); 3820 PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg)); 3821 PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg)); 3822 PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg)); 3823 PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2)); 3824 if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure)); 3825 3826 switch (cell) { 3827 case DM_POLYTOPE_POINT: 3828 case DM_POLYTOPE_SEGMENT: 3829 case DM_POLYTOPE_POINT_PRISM_TENSOR: 3830 case DM_POLYTOPE_TRIANGLE: 3831 case DM_POLYTOPE_QUADRILATERAL: 3832 case DM_POLYTOPE_TETRAHEDRON: 3833 case DM_POLYTOPE_HEXAHEDRON: 3834 *useCoordSpace = PETSC_TRUE; 3835 break; 3836 default: 3837 *useCoordSpace = PETSC_FALSE; 3838 break; 3839 } 3840 3841 if (fflg) { 3842 DM dmnew; 3843 3844 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, plexname, interpolate, &dmnew)); 3845 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3846 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3847 } else if (refDomain) { 3848 PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell)); 3849 } else if (bdfflg) { 3850 DM bdm, dmnew; 3851 3852 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, plexname, interpolate, &bdm)); 3853 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_")); 3854 PetscCall(DMSetFromOptions(bdm)); 3855 PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew)); 3856 PetscCall(DMDestroy(&bdm)); 3857 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3858 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3859 } else { 3860 PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape])); 3861 switch (shape) { 3862 case DM_SHAPE_BOX: 3863 case DM_SHAPE_ANNULUS: { 3864 PetscInt faces[3] = {0, 0, 0}; 3865 PetscReal lower[3] = {0, 0, 0}; 3866 PetscReal upper[3] = {1, 1, 1}; 3867 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 3868 PetscBool isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE; 3869 PetscInt i, n; 3870 3871 n = dim; 3872 for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim); 3873 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 3874 n = 3; 3875 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 3876 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3877 n = 3; 3878 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 3879 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3880 n = 3; 3881 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 3882 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3883 3884 PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented"); 3885 if (isAnnular) 3886 for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC; 3887 3888 switch (cell) { 3889 case DM_POLYTOPE_TRI_PRISM_TENSOR: 3890 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt)); 3891 if (!interpolate) { 3892 DM udm; 3893 3894 PetscCall(DMPlexUninterpolate(dm, &udm)); 3895 PetscCall(DMPlexReplace_Internal(dm, &udm)); 3896 } 3897 break; 3898 default: 3899 PetscCall(DMPlexCreateBoxMesh_Internal(dm, dim, simplex, faces, lower, upper, bdt, interpolate)); 3900 break; 3901 } 3902 if (isAnnular) { 3903 DM cdm; 3904 PetscDS cds; 3905 PetscScalar bounds[2] = {lower[0], upper[0]}; 3906 3907 // Fix coordinates for annular region 3908 PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 3909 PetscCall(DMSetCellCoordinatesLocal(dm, NULL)); 3910 PetscCall(DMSetCellCoordinates(dm, NULL)); 3911 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, NULL)); 3912 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3913 PetscCall(DMGetDS(cdm, &cds)); 3914 PetscCall(PetscDSSetConstants(cds, 2, bounds)); 3915 PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus)); 3916 } 3917 } break; 3918 case DM_SHAPE_BOX_SURFACE: { 3919 PetscInt faces[3] = {0, 0, 0}; 3920 PetscReal lower[3] = {0, 0, 0}; 3921 PetscReal upper[3] = {1, 1, 1}; 3922 PetscInt i, n; 3923 3924 n = dim + 1; 3925 for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1)); 3926 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 3927 n = 3; 3928 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 3929 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); 3930 n = 3; 3931 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 3932 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); 3933 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate)); 3934 } break; 3935 case DM_SHAPE_SPHERE: { 3936 PetscReal R = 1.0; 3937 3938 PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg)); 3939 PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R)); 3940 } break; 3941 case DM_SHAPE_BALL: { 3942 PetscReal R = 1.0; 3943 3944 PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg)); 3945 PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R)); 3946 } break; 3947 case DM_SHAPE_CYLINDER: { 3948 DMBoundaryType bdt = DM_BOUNDARY_NONE; 3949 PetscInt Nw = 6; 3950 3951 PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL)); 3952 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL)); 3953 switch (cell) { 3954 case DM_POLYTOPE_TRI_PRISM_TENSOR: 3955 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate)); 3956 break; 3957 default: 3958 PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt)); 3959 break; 3960 } 3961 } break; 3962 case DM_SHAPE_SCHWARZ_P: // fallthrough 3963 case DM_SHAPE_GYROID: { 3964 PetscInt extent[3] = {1, 1, 1}, refine = 0, layers = 0, three; 3965 PetscReal thickness = 0.; 3966 DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 3967 DMPlexTPSType tps_type = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID; 3968 PetscBool tps_distribute; 3969 PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL)); 3970 PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL)); 3971 PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL)); 3972 PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL)); 3973 PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL)); 3974 PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute)); 3975 PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL)); 3976 PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness)); 3977 } break; 3978 case DM_SHAPE_DOUBLET: { 3979 DM dmnew; 3980 PetscReal rl = 0.0; 3981 3982 PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL)); 3983 PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew)); 3984 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3985 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3986 } break; 3987 case DM_SHAPE_HYPERCUBIC: { 3988 PetscInt *edges; 3989 PetscReal *lower, *upper; 3990 DMBoundaryType *bdt; 3991 PetscInt n, d; 3992 3993 *useCoordSpace = PETSC_FALSE; 3994 PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt)); 3995 for (d = 0; d < dim; ++d) { 3996 edges[d] = 1; 3997 lower[d] = 0.; 3998 upper[d] = 1.; 3999 bdt[d] = DM_BOUNDARY_PERIODIC; 4000 } 4001 n = dim; 4002 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg)); 4003 n = dim; 4004 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4005 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4006 n = dim; 4007 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4008 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4009 n = dim; 4010 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4011 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4012 PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt)); 4013 PetscCall(PetscFree4(edges, lower, upper, bdt)); 4014 } break; 4015 default: 4016 SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]); 4017 } 4018 } 4019 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4020 if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname)); 4021 PetscFunctionReturn(0); 4022 } 4023 4024 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4025 { 4026 DM_Plex *mesh = (DM_Plex *)dm->data; 4027 PetscBool flg, flg2; 4028 char bdLabel[PETSC_MAX_PATH_LEN]; 4029 4030 PetscFunctionBegin; 4031 /* Handle viewing */ 4032 PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL)); 4033 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0)); 4034 PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL)); 4035 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0)); 4036 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0)); 4037 PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg)); 4038 if (flg) PetscCall(PetscLogDefaultBegin()); 4039 /* Labeling */ 4040 PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg)); 4041 if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel)); 4042 /* Point Location */ 4043 PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL)); 4044 /* Partitioning and distribution */ 4045 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL)); 4046 /* Generation and remeshing */ 4047 PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL)); 4048 /* Projection behavior */ 4049 PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0)); 4050 PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL)); 4051 /* Checking structure */ 4052 { 4053 PetscBool all = PETSC_FALSE; 4054 4055 PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL)); 4056 if (all) { 4057 PetscCall(DMPlexCheck(dm)); 4058 } else { 4059 PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2)); 4060 if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm)); 4061 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)); 4062 if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0)); 4063 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)); 4064 if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0)); 4065 PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2)); 4066 if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm)); 4067 PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2)); 4068 if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 4069 PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2)); 4070 if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm)); 4071 } 4072 PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2)); 4073 if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE)); 4074 } 4075 { 4076 PetscReal scale = 1.0; 4077 4078 PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg)); 4079 if (flg) { 4080 Vec coordinates, coordinatesLocal; 4081 4082 PetscCall(DMGetCoordinates(dm, &coordinates)); 4083 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 4084 PetscCall(VecScale(coordinates, scale)); 4085 PetscCall(VecScale(coordinatesLocal, scale)); 4086 } 4087 } 4088 PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner)); 4089 PetscFunctionReturn(0); 4090 } 4091 4092 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap) 4093 { 4094 PetscInt numOvLabels = 16, numOvExLabels = 16; 4095 char *ovLabelNames[16], *ovExLabelNames[16]; 4096 PetscInt numOvValues = 16, numOvExValues = 16, l; 4097 PetscBool flg; 4098 4099 PetscFunctionBegin; 4100 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0)); 4101 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg)); 4102 if (!flg) numOvLabels = 0; 4103 if (numOvLabels) { 4104 ((DM_Plex *)dm->data)->numOvLabels = numOvLabels; 4105 for (l = 0; l < numOvLabels; ++l) { 4106 PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l])); 4107 PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]); 4108 PetscCall(PetscFree(ovLabelNames[l])); 4109 } 4110 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg)); 4111 if (!flg) numOvValues = 0; 4112 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); 4113 4114 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg)); 4115 if (!flg) numOvExLabels = 0; 4116 ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels; 4117 for (l = 0; l < numOvExLabels; ++l) { 4118 PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l])); 4119 PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]); 4120 PetscCall(PetscFree(ovExLabelNames[l])); 4121 } 4122 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg)); 4123 if (!flg) numOvExValues = 0; 4124 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); 4125 } 4126 PetscFunctionReturn(0); 4127 } 4128 4129 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4130 { 4131 PetscFunctionList ordlist; 4132 char oname[256]; 4133 PetscReal volume = -1.0; 4134 PetscInt prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim; 4135 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; 4136 DMPlexReorderDefaultFlag reorder; 4137 4138 PetscFunctionBegin; 4139 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options"); 4140 if (dm->cloneOpts) goto non_refine; 4141 /* Handle automatic creation */ 4142 PetscCall(DMGetDimension(dm, &dim)); 4143 if (dim < 0) { 4144 PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm)); 4145 created = PETSC_TRUE; 4146 } 4147 PetscCall(DMGetDimension(dm, &dim)); 4148 /* Handle interpolation before distribution */ 4149 PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg)); 4150 if (flg) { 4151 DMPlexInterpolatedFlag interpolated; 4152 4153 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 4154 if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) { 4155 DM udm; 4156 4157 PetscCall(DMPlexUninterpolate(dm, &udm)); 4158 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4159 } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) { 4160 DM idm; 4161 4162 PetscCall(DMPlexInterpolate(dm, &idm)); 4163 PetscCall(DMPlexReplace_Internal(dm, &idm)); 4164 } 4165 } 4166 /* Handle DMPlex refinement before distribution */ 4167 PetscCall(PetscOptionsBool("-dm_refine_ignore_model", "Flag to ignore the geometry model when refining", "DMCreate", ignoreModel, &ignoreModel, &flg)); 4168 if (flg) ((DM_Plex *)dm->data)->ignoreModel = ignoreModel; 4169 PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig)); 4170 PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0)); 4171 PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4172 PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg)); 4173 if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform)); 4174 PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg)); 4175 if (flg) { 4176 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE)); 4177 PetscCall(DMPlexSetRefinementLimit(dm, volume)); 4178 prerefine = PetscMax(prerefine, 1); 4179 } 4180 for (r = 0; r < prerefine; ++r) { 4181 DM rdm; 4182 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4183 4184 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4185 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4186 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4187 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4188 if (coordFunc && remap) { 4189 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4190 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4191 } 4192 } 4193 PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig)); 4194 /* Handle DMPlex extrusion before distribution */ 4195 PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0)); 4196 if (extLayers) { 4197 DM edm; 4198 4199 PetscCall(DMExtrude(dm, extLayers, &edm)); 4200 PetscCall(DMPlexReplace_Internal(dm, &edm)); 4201 ((DM_Plex *)dm->data)->coordFunc = NULL; 4202 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4203 extLayers = 0; 4204 PetscCall(DMGetDimension(dm, &dim)); 4205 } 4206 /* Handle DMPlex reordering before distribution */ 4207 PetscCall(DMPlexReorderGetDefault(dm, &reorder)); 4208 PetscCall(MatGetOrderingList(&ordlist)); 4209 PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname))); 4210 PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg)); 4211 if (reorder == DMPLEX_REORDER_DEFAULT_TRUE || flg) { 4212 DM pdm; 4213 IS perm; 4214 4215 PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm)); 4216 PetscCall(DMPlexPermute(dm, perm, &pdm)); 4217 PetscCall(ISDestroy(&perm)); 4218 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4219 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4220 } 4221 /* Handle DMPlex distribution */ 4222 PetscCall(DMPlexDistributeGetDefault(dm, &distribute)); 4223 PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL)); 4224 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 4225 if (distribute) { 4226 DM pdm = NULL; 4227 PetscPartitioner part; 4228 4229 PetscCall(DMPlexGetPartitioner(dm, &part)); 4230 PetscCall(PetscPartitionerSetFromOptions(part)); 4231 PetscCall(DMPlexDistribute(dm, overlap, NULL, &pdm)); 4232 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4233 } 4234 /* Create coordinate space */ 4235 if (created) { 4236 DM_Plex *mesh = (DM_Plex *)dm->data; 4237 PetscInt degree = 1; 4238 PetscInt height = 0; 4239 DM cdm; 4240 PetscBool flg; 4241 4242 PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg)); 4243 PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, °ree, NULL)); 4244 if (coordSpace) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, mesh->coordFunc)); 4245 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4246 if (flg && !coordSpace) { 4247 PetscDS cds; 4248 PetscObject obj; 4249 PetscClassId id; 4250 4251 PetscCall(DMGetDS(cdm, &cds)); 4252 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4253 PetscCall(PetscObjectGetClassId(obj, &id)); 4254 if (id == PETSCFE_CLASSID) { 4255 PetscContainer dummy; 4256 4257 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy)); 4258 PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates")); 4259 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy)); 4260 PetscCall(PetscContainerDestroy(&dummy)); 4261 PetscCall(DMClearDS(cdm)); 4262 } 4263 mesh->coordFunc = NULL; 4264 } 4265 PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "", dm->sparseLocalize, &dm->sparseLocalize, &flg)); 4266 PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg)); 4267 if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height)); 4268 PetscCall(DMLocalizeCoordinates(dm)); 4269 } 4270 /* Handle DMPlex refinement */ 4271 remap = PETSC_TRUE; 4272 PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0)); 4273 PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4274 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0)); 4275 if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4276 if (refine && isHierarchy) { 4277 DM *dms, coarseDM; 4278 4279 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 4280 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 4281 PetscCall(PetscMalloc1(refine, &dms)); 4282 PetscCall(DMRefineHierarchy(dm, refine, dms)); 4283 /* Total hack since we do not pass in a pointer */ 4284 PetscCall(DMPlexSwap_Static(dm, dms[refine - 1])); 4285 if (refine == 1) { 4286 PetscCall(DMSetCoarseDM(dm, dms[0])); 4287 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4288 } else { 4289 PetscCall(DMSetCoarseDM(dm, dms[refine - 2])); 4290 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4291 PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1])); 4292 PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE)); 4293 } 4294 PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM)); 4295 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 4296 /* Free DMs */ 4297 for (r = 0; r < refine; ++r) { 4298 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4299 PetscCall(DMDestroy(&dms[r])); 4300 } 4301 PetscCall(PetscFree(dms)); 4302 } else { 4303 for (r = 0; r < refine; ++r) { 4304 DM rdm; 4305 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4306 4307 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4308 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4309 /* Total hack since we do not pass in a pointer */ 4310 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4311 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4312 if (coordFunc && remap) { 4313 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4314 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4315 } 4316 } 4317 } 4318 /* Handle DMPlex coarsening */ 4319 PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0)); 4320 PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0)); 4321 if (coarsen && isHierarchy) { 4322 DM *dms; 4323 4324 PetscCall(PetscMalloc1(coarsen, &dms)); 4325 PetscCall(DMCoarsenHierarchy(dm, coarsen, dms)); 4326 /* Free DMs */ 4327 for (r = 0; r < coarsen; ++r) { 4328 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4329 PetscCall(DMDestroy(&dms[r])); 4330 } 4331 PetscCall(PetscFree(dms)); 4332 } else { 4333 for (r = 0; r < coarsen; ++r) { 4334 DM cdm; 4335 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4336 4337 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4338 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm)); 4339 /* Total hack since we do not pass in a pointer */ 4340 PetscCall(DMPlexReplace_Internal(dm, &cdm)); 4341 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4342 if (coordFunc) { 4343 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4344 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4345 } 4346 } 4347 } 4348 /* Handle ghost cells */ 4349 PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL)); 4350 if (ghostCells) { 4351 DM gdm; 4352 char lname[PETSC_MAX_PATH_LEN]; 4353 4354 lname[0] = '\0'; 4355 PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg)); 4356 PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm)); 4357 PetscCall(DMPlexReplace_Internal(dm, &gdm)); 4358 } 4359 /* Handle 1D order */ 4360 if (reorder != DMPLEX_REORDER_DEFAULT_FALSE && dim == 1) { 4361 DM cdm, rdm; 4362 PetscDS cds; 4363 PetscObject obj; 4364 PetscClassId id = PETSC_OBJECT_CLASSID; 4365 IS perm; 4366 PetscInt Nf; 4367 PetscBool distributed; 4368 4369 PetscCall(DMPlexIsDistributed(dm, &distributed)); 4370 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4371 PetscCall(DMGetDS(cdm, &cds)); 4372 PetscCall(PetscDSGetNumFields(cds, &Nf)); 4373 if (Nf) { 4374 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4375 PetscCall(PetscObjectGetClassId(obj, &id)); 4376 } 4377 if (!distributed && id != PETSCFE_CLASSID) { 4378 PetscCall(DMPlexGetOrdering1D(dm, &perm)); 4379 PetscCall(DMPlexPermute(dm, perm, &rdm)); 4380 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4381 PetscCall(ISDestroy(&perm)); 4382 } 4383 } 4384 /* Handle */ 4385 non_refine: 4386 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4387 PetscOptionsHeadEnd(); 4388 PetscFunctionReturn(0); 4389 } 4390 4391 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec) 4392 { 4393 PetscFunctionBegin; 4394 PetscCall(DMCreateGlobalVector_Section_Private(dm, vec)); 4395 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 4396 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex)); 4397 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native)); 4398 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex)); 4399 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native)); 4400 PetscFunctionReturn(0); 4401 } 4402 4403 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec) 4404 { 4405 PetscFunctionBegin; 4406 PetscCall(DMCreateLocalVector_Section_Private(dm, vec)); 4407 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local)); 4408 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local)); 4409 PetscFunctionReturn(0); 4410 } 4411 4412 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 4413 { 4414 PetscInt depth, d; 4415 4416 PetscFunctionBegin; 4417 PetscCall(DMPlexGetDepth(dm, &depth)); 4418 if (depth == 1) { 4419 PetscCall(DMGetDimension(dm, &d)); 4420 if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4421 else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd)); 4422 else { 4423 *pStart = 0; 4424 *pEnd = 0; 4425 } 4426 } else { 4427 PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4428 } 4429 PetscFunctionReturn(0); 4430 } 4431 4432 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 4433 { 4434 PetscSF sf; 4435 PetscInt niranks, njranks, n; 4436 const PetscMPIInt *iranks, *jranks; 4437 DM_Plex *data = (DM_Plex *)dm->data; 4438 4439 PetscFunctionBegin; 4440 PetscCall(DMGetPointSF(dm, &sf)); 4441 if (!data->neighbors) { 4442 PetscCall(PetscSFSetUp(sf)); 4443 PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL)); 4444 PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL)); 4445 PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors)); 4446 PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks)); 4447 PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks)); 4448 n = njranks + niranks; 4449 PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1)); 4450 /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */ 4451 PetscCall(PetscMPIIntCast(n, data->neighbors)); 4452 } 4453 if (nranks) *nranks = data->neighbors[0]; 4454 if (ranks) { 4455 if (data->neighbors[0]) *ranks = data->neighbors + 1; 4456 else *ranks = NULL; 4457 } 4458 PetscFunctionReturn(0); 4459 } 4460 4461 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec); 4462 4463 static PetscErrorCode DMInitialize_Plex(DM dm) 4464 { 4465 PetscFunctionBegin; 4466 dm->ops->view = DMView_Plex; 4467 dm->ops->load = DMLoad_Plex; 4468 dm->ops->setfromoptions = DMSetFromOptions_Plex; 4469 dm->ops->clone = DMClone_Plex; 4470 dm->ops->setup = DMSetUp_Plex; 4471 dm->ops->createlocalsection = DMCreateLocalSection_Plex; 4472 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_Plex; 4473 dm->ops->createglobalvector = DMCreateGlobalVector_Plex; 4474 dm->ops->createlocalvector = DMCreateLocalVector_Plex; 4475 dm->ops->getlocaltoglobalmapping = NULL; 4476 dm->ops->createfieldis = NULL; 4477 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Plex; 4478 dm->ops->createcoordinatefield = DMCreateCoordinateField_Plex; 4479 dm->ops->getcoloring = NULL; 4480 dm->ops->creatematrix = DMCreateMatrix_Plex; 4481 dm->ops->createinterpolation = DMCreateInterpolation_Plex; 4482 dm->ops->createmassmatrix = DMCreateMassMatrix_Plex; 4483 dm->ops->createmassmatrixlumped = DMCreateMassMatrixLumped_Plex; 4484 dm->ops->createinjection = DMCreateInjection_Plex; 4485 dm->ops->refine = DMRefine_Plex; 4486 dm->ops->coarsen = DMCoarsen_Plex; 4487 dm->ops->refinehierarchy = DMRefineHierarchy_Plex; 4488 dm->ops->coarsenhierarchy = DMCoarsenHierarchy_Plex; 4489 dm->ops->extrude = DMExtrude_Plex; 4490 dm->ops->globaltolocalbegin = NULL; 4491 dm->ops->globaltolocalend = NULL; 4492 dm->ops->localtoglobalbegin = NULL; 4493 dm->ops->localtoglobalend = NULL; 4494 dm->ops->destroy = DMDestroy_Plex; 4495 dm->ops->createsubdm = DMCreateSubDM_Plex; 4496 dm->ops->createsuperdm = DMCreateSuperDM_Plex; 4497 dm->ops->getdimpoints = DMGetDimPoints_Plex; 4498 dm->ops->locatepoints = DMLocatePoints_Plex; 4499 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_Plex; 4500 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex; 4501 dm->ops->projectfieldlocal = DMProjectFieldLocal_Plex; 4502 dm->ops->projectfieldlabellocal = DMProjectFieldLabelLocal_Plex; 4503 dm->ops->projectbdfieldlabellocal = DMProjectBdFieldLabelLocal_Plex; 4504 dm->ops->computel2diff = DMComputeL2Diff_Plex; 4505 dm->ops->computel2gradientdiff = DMComputeL2GradientDiff_Plex; 4506 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_Plex; 4507 dm->ops->getneighbors = DMGetNeighbors_Plex; 4508 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex)); 4509 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex)); 4510 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex)); 4511 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex)); 4512 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 4513 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex)); 4514 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex)); 4515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex)); 4516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex)); 4517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex)); 4518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 4519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex)); 4520 PetscFunctionReturn(0); 4521 } 4522 4523 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm) 4524 { 4525 DM_Plex *mesh = (DM_Plex *)dm->data; 4526 PetscSF face_sf; 4527 4528 PetscFunctionBegin; 4529 mesh->refct++; 4530 (*newdm)->data = mesh; 4531 PetscCall(DMPlexGetPeriodicFaceSF(dm, &face_sf)); 4532 PetscCall(DMPlexSetPeriodicFaceSF(*newdm, face_sf)); 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