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