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