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