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 DMReorderDefaultFlag 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 PetscCheck(dim >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " should be in [0, infinity)", dim); 3887 PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg)); 3888 PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg)); 3889 PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg)); 3890 PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2)); 3891 if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure)); 3892 3893 switch (cell) { 3894 case DM_POLYTOPE_POINT: 3895 case DM_POLYTOPE_SEGMENT: 3896 case DM_POLYTOPE_POINT_PRISM_TENSOR: 3897 case DM_POLYTOPE_TRIANGLE: 3898 case DM_POLYTOPE_QUADRILATERAL: 3899 case DM_POLYTOPE_TETRAHEDRON: 3900 case DM_POLYTOPE_HEXAHEDRON: 3901 *useCoordSpace = PETSC_TRUE; 3902 break; 3903 default: 3904 *useCoordSpace = PETSC_FALSE; 3905 break; 3906 } 3907 3908 if (fflg) { 3909 DM dmnew; 3910 3911 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, plexname, interpolate, &dmnew)); 3912 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3913 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3914 } else if (refDomain) { 3915 PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell)); 3916 } else if (bdfflg) { 3917 DM bdm, dmnew; 3918 3919 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, plexname, interpolate, &bdm)); 3920 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_")); 3921 PetscCall(DMSetFromOptions(bdm)); 3922 PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew)); 3923 PetscCall(DMDestroy(&bdm)); 3924 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3925 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3926 } else { 3927 PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape])); 3928 switch (shape) { 3929 case DM_SHAPE_BOX: 3930 case DM_SHAPE_ZBOX: 3931 case DM_SHAPE_ANNULUS: { 3932 PetscInt faces[3] = {0, 0, 0}; 3933 PetscReal lower[3] = {0, 0, 0}; 3934 PetscReal upper[3] = {1, 1, 1}; 3935 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 3936 PetscBool isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE; 3937 PetscInt i, n; 3938 3939 n = dim; 3940 for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim); 3941 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 3942 n = 3; 3943 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 3944 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3945 n = 3; 3946 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 3947 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3948 n = 3; 3949 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 3950 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3951 3952 PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented"); 3953 if (isAnnular) 3954 for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC; 3955 3956 switch (cell) { 3957 case DM_POLYTOPE_TRI_PRISM_TENSOR: 3958 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt)); 3959 if (!interpolate) { 3960 DM udm; 3961 3962 PetscCall(DMPlexUninterpolate(dm, &udm)); 3963 PetscCall(DMPlexReplace_Internal(dm, &udm)); 3964 } 3965 break; 3966 default: 3967 PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate)); 3968 break; 3969 } 3970 if (isAnnular) { 3971 DM cdm; 3972 PetscDS cds; 3973 PetscScalar bounds[2] = {lower[0], upper[0]}; 3974 3975 // Fix coordinates for annular region 3976 PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 3977 PetscCall(DMSetCellCoordinatesLocal(dm, NULL)); 3978 PetscCall(DMSetCellCoordinates(dm, NULL)); 3979 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 3980 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3981 PetscCall(DMGetDS(cdm, &cds)); 3982 PetscCall(PetscDSSetConstants(cds, 2, bounds)); 3983 PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus)); 3984 } 3985 } break; 3986 case DM_SHAPE_BOX_SURFACE: { 3987 PetscInt faces[3] = {0, 0, 0}; 3988 PetscReal lower[3] = {0, 0, 0}; 3989 PetscReal upper[3] = {1, 1, 1}; 3990 PetscInt i, n; 3991 3992 n = dim + 1; 3993 for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1)); 3994 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 3995 n = 3; 3996 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 3997 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); 3998 n = 3; 3999 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4000 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); 4001 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate)); 4002 } break; 4003 case DM_SHAPE_SPHERE: { 4004 PetscReal R = 1.0; 4005 4006 PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg)); 4007 PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R)); 4008 } break; 4009 case DM_SHAPE_BALL: { 4010 PetscReal R = 1.0; 4011 4012 PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg)); 4013 PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R)); 4014 } break; 4015 case DM_SHAPE_CYLINDER: { 4016 DMBoundaryType bdt = DM_BOUNDARY_NONE; 4017 PetscInt Nw = 6; 4018 4019 PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL)); 4020 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL)); 4021 switch (cell) { 4022 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4023 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate)); 4024 break; 4025 default: 4026 PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt)); 4027 break; 4028 } 4029 } break; 4030 case DM_SHAPE_SCHWARZ_P: // fallthrough 4031 case DM_SHAPE_GYROID: { 4032 PetscInt extent[3] = {1, 1, 1}, refine = 0, layers = 0, three; 4033 PetscReal thickness = 0.; 4034 DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4035 DMPlexTPSType tps_type = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID; 4036 PetscBool tps_distribute; 4037 PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL)); 4038 PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL)); 4039 PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL)); 4040 PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL)); 4041 PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL)); 4042 PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute)); 4043 PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL)); 4044 PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness)); 4045 } break; 4046 case DM_SHAPE_DOUBLET: { 4047 DM dmnew; 4048 PetscReal rl = 0.0; 4049 4050 PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL)); 4051 PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew)); 4052 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4053 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4054 } break; 4055 case DM_SHAPE_HYPERCUBIC: { 4056 PetscInt *edges; 4057 PetscReal *lower, *upper; 4058 DMBoundaryType *bdt; 4059 PetscInt n, d; 4060 4061 *useCoordSpace = PETSC_FALSE; 4062 PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt)); 4063 for (d = 0; d < dim; ++d) { 4064 edges[d] = 1; 4065 lower[d] = 0.; 4066 upper[d] = 1.; 4067 bdt[d] = DM_BOUNDARY_PERIODIC; 4068 } 4069 n = dim; 4070 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg)); 4071 n = dim; 4072 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4073 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4074 n = dim; 4075 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4076 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4077 n = dim; 4078 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4079 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4080 PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt)); 4081 PetscCall(PetscFree4(edges, lower, upper, bdt)); 4082 } break; 4083 default: 4084 SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]); 4085 } 4086 } 4087 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4088 if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname)); 4089 // Allow label creation 4090 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg)); 4091 if (flg) { 4092 DMLabel label; 4093 PetscInt points[1024], n = 1024; 4094 char fulloption[PETSC_MAX_PATH_LEN]; 4095 const char *name = &option[14]; 4096 4097 PetscCall(DMCreateLabel(dm, name)); 4098 PetscCall(DMGetLabel(dm, name, &label)); 4099 fulloption[0] = '-'; 4100 fulloption[1] = 0; 4101 PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN)); 4102 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL)); 4103 for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1)); 4104 } 4105 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 4106 PetscFunctionReturn(PETSC_SUCCESS); 4107 } 4108 4109 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4110 { 4111 DM_Plex *mesh = (DM_Plex *)dm->data; 4112 PetscBool flg, flg2; 4113 char bdLabel[PETSC_MAX_PATH_LEN]; 4114 char method[PETSC_MAX_PATH_LEN]; 4115 4116 PetscFunctionBegin; 4117 /* Handle viewing */ 4118 PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL)); 4119 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0)); 4120 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0)); 4121 PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL)); 4122 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0)); 4123 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0)); 4124 PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg)); 4125 if (flg) PetscCall(PetscLogDefaultBegin()); 4126 /* Labeling */ 4127 PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg)); 4128 if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel)); 4129 /* Point Location */ 4130 PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL)); 4131 /* Partitioning and distribution */ 4132 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL)); 4133 /* Reordering */ 4134 PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg)); 4135 if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE)); 4136 PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg)); 4137 if (flg) PetscCall(DMReorderSectionSetType(dm, method)); 4138 /* Generation and remeshing */ 4139 PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL)); 4140 /* Projection behavior */ 4141 PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0)); 4142 PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL)); 4143 /* Checking structure */ 4144 { 4145 PetscBool all = PETSC_FALSE; 4146 4147 PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL)); 4148 if (all) { 4149 PetscCall(DMPlexCheck(dm)); 4150 } else { 4151 PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2)); 4152 if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm)); 4153 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)); 4154 if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0)); 4155 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)); 4156 if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0)); 4157 PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2)); 4158 if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm)); 4159 PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2)); 4160 if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 4161 PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2)); 4162 if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm)); 4163 } 4164 PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2)); 4165 if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE)); 4166 } 4167 { 4168 PetscReal scale = 1.0; 4169 4170 PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg)); 4171 if (flg) { 4172 Vec coordinates, coordinatesLocal; 4173 4174 PetscCall(DMGetCoordinates(dm, &coordinates)); 4175 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 4176 PetscCall(VecScale(coordinates, scale)); 4177 PetscCall(VecScale(coordinatesLocal, scale)); 4178 } 4179 } 4180 PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner)); 4181 PetscFunctionReturn(PETSC_SUCCESS); 4182 } 4183 4184 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap) 4185 { 4186 PetscInt numOvLabels = 16, numOvExLabels = 16; 4187 char *ovLabelNames[16], *ovExLabelNames[16]; 4188 PetscInt numOvValues = 16, numOvExValues = 16, l; 4189 PetscBool flg; 4190 4191 PetscFunctionBegin; 4192 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0)); 4193 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg)); 4194 if (!flg) numOvLabels = 0; 4195 if (numOvLabels) { 4196 ((DM_Plex *)dm->data)->numOvLabels = numOvLabels; 4197 for (l = 0; l < numOvLabels; ++l) { 4198 PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l])); 4199 PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]); 4200 PetscCall(PetscFree(ovLabelNames[l])); 4201 } 4202 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg)); 4203 if (!flg) numOvValues = 0; 4204 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); 4205 4206 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg)); 4207 if (!flg) numOvExLabels = 0; 4208 ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels; 4209 for (l = 0; l < numOvExLabels; ++l) { 4210 PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l])); 4211 PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]); 4212 PetscCall(PetscFree(ovExLabelNames[l])); 4213 } 4214 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg)); 4215 if (!flg) numOvExValues = 0; 4216 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); 4217 } 4218 PetscFunctionReturn(PETSC_SUCCESS); 4219 } 4220 4221 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4222 { 4223 PetscFunctionList ordlist; 4224 char oname[256]; 4225 char sublabelname[PETSC_MAX_PATH_LEN] = ""; 4226 DMReorderDefaultFlag reorder; 4227 PetscReal volume = -1.0; 4228 PetscInt prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim; 4229 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; 4230 4231 PetscFunctionBegin; 4232 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options"); 4233 if (dm->cloneOpts) goto non_refine; 4234 /* Handle automatic creation */ 4235 PetscCall(DMGetDimension(dm, &dim)); 4236 if (dim < 0) { 4237 PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm)); 4238 created = PETSC_TRUE; 4239 } 4240 PetscCall(DMGetDimension(dm, &dim)); 4241 /* Handle interpolation before distribution */ 4242 PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg)); 4243 if (flg) { 4244 DMPlexInterpolatedFlag interpolated; 4245 4246 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 4247 if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) { 4248 DM udm; 4249 4250 PetscCall(DMPlexUninterpolate(dm, &udm)); 4251 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4252 } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) { 4253 DM idm; 4254 4255 PetscCall(DMPlexInterpolate(dm, &idm)); 4256 PetscCall(DMPlexReplace_Internal(dm, &idm)); 4257 } 4258 } 4259 // Handle submesh selection before distribution 4260 PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg)); 4261 if (flg) { 4262 DM subdm; 4263 DMLabel label; 4264 IS valueIS, pointIS; 4265 const PetscInt *values, *points; 4266 PetscBool markedFaces = PETSC_FALSE; 4267 PetscInt Nv, value, Np; 4268 4269 PetscCall(DMGetLabel(dm, sublabelname, &label)); 4270 PetscCall(DMLabelGetNumValues(label, &Nv)); 4271 PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv); 4272 PetscCall(DMLabelGetValueIS(label, &valueIS)); 4273 PetscCall(ISGetIndices(valueIS, &values)); 4274 value = values[0]; 4275 PetscCall(ISRestoreIndices(valueIS, &values)); 4276 PetscCall(ISDestroy(&valueIS)); 4277 PetscCall(DMLabelGetStratumSize(label, value, &Np)); 4278 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 4279 PetscCall(ISGetIndices(pointIS, &points)); 4280 for (PetscInt p = 0; p < Np; ++p) { 4281 PetscInt pdepth; 4282 4283 PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth)); 4284 if (pdepth) { 4285 markedFaces = PETSC_TRUE; 4286 break; 4287 } 4288 } 4289 PetscCall(ISRestoreIndices(pointIS, &points)); 4290 PetscCall(ISDestroy(&pointIS)); 4291 PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm)); 4292 PetscCall(DMPlexReplace_Internal(dm, &subdm)); 4293 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4294 } 4295 /* Handle DMPlex refinement before distribution */ 4296 PetscCall(PetscOptionsBool("-dm_refine_ignore_model", "Flag to ignore the geometry model when refining", "DMCreate", ignoreModel, &ignoreModel, &flg)); 4297 if (flg) ((DM_Plex *)dm->data)->ignoreModel = ignoreModel; 4298 PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig)); 4299 PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0)); 4300 PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4301 PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg)); 4302 if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform)); 4303 PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg)); 4304 if (flg) { 4305 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE)); 4306 PetscCall(DMPlexSetRefinementLimit(dm, volume)); 4307 prerefine = PetscMax(prerefine, 1); 4308 } 4309 if (prerefine) PetscCall(DMLocalizeCoordinates(dm)); 4310 for (r = 0; r < prerefine; ++r) { 4311 DM rdm; 4312 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4313 4314 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4315 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4316 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4317 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4318 if (coordFunc && remap) { 4319 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4320 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4321 } 4322 } 4323 PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig)); 4324 /* Handle DMPlex extrusion before distribution */ 4325 PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0)); 4326 if (extLayers) { 4327 DM edm; 4328 4329 PetscCall(DMExtrude(dm, extLayers, &edm)); 4330 PetscCall(DMPlexReplace_Internal(dm, &edm)); 4331 ((DM_Plex *)dm->data)->coordFunc = NULL; 4332 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4333 extLayers = 0; 4334 PetscCall(DMGetDimension(dm, &dim)); 4335 } 4336 /* Handle DMPlex reordering before distribution */ 4337 PetscCall(DMPlexReorderGetDefault(dm, &reorder)); 4338 PetscCall(MatGetOrderingList(&ordlist)); 4339 PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname))); 4340 PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg)); 4341 if (reorder == DM_REORDER_DEFAULT_TRUE || flg) { 4342 DM pdm; 4343 IS perm; 4344 4345 PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm)); 4346 PetscCall(DMPlexPermute(dm, perm, &pdm)); 4347 PetscCall(ISDestroy(&perm)); 4348 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4349 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4350 } 4351 /* Handle DMPlex distribution */ 4352 PetscCall(DMPlexDistributeGetDefault(dm, &distribute)); 4353 PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL)); 4354 PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL)); 4355 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 4356 if (distribute) { 4357 DM pdm = NULL; 4358 PetscPartitioner part; 4359 PetscSF sfMigration; 4360 4361 PetscCall(DMPlexGetPartitioner(dm, &part)); 4362 PetscCall(PetscPartitionerSetFromOptions(part)); 4363 PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm)); 4364 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4365 if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration)); 4366 PetscCall(PetscSFDestroy(&sfMigration)); 4367 } 4368 /* Must check CEED options before creating function space for coordinates */ 4369 { 4370 PetscBool useCeed = PETSC_FALSE, flg; 4371 4372 PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg)); 4373 if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed)); 4374 } 4375 /* Create coordinate space */ 4376 if (created) { 4377 DM_Plex *mesh = (DM_Plex *)dm->data; 4378 PetscInt degree = 1, deg; 4379 PetscInt height = 0; 4380 DM cdm; 4381 PetscBool flg; 4382 4383 PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg)); 4384 PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, °ree, NULL)); 4385 PetscCall(DMGetCoordinateDegree_Internal(dm, °)); 4386 if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, mesh->coordFunc)); 4387 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4388 if (flg && !coordSpace) { 4389 PetscDS cds; 4390 PetscObject obj; 4391 PetscClassId id; 4392 4393 PetscCall(DMGetDS(cdm, &cds)); 4394 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4395 PetscCall(PetscObjectGetClassId(obj, &id)); 4396 if (id == PETSCFE_CLASSID) { 4397 PetscContainer dummy; 4398 4399 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy)); 4400 PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates")); 4401 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy)); 4402 PetscCall(PetscContainerDestroy(&dummy)); 4403 PetscCall(DMClearDS(cdm)); 4404 } 4405 mesh->coordFunc = NULL; 4406 } 4407 PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "", dm->sparseLocalize, &dm->sparseLocalize, &flg)); 4408 PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg)); 4409 if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height)); 4410 PetscCall(DMLocalizeCoordinates(dm)); 4411 } 4412 /* Handle DMPlex refinement */ 4413 remap = PETSC_TRUE; 4414 PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0)); 4415 PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4416 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0)); 4417 if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4418 if (refine && isHierarchy) { 4419 DM *dms, coarseDM; 4420 4421 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 4422 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 4423 PetscCall(PetscMalloc1(refine, &dms)); 4424 PetscCall(DMRefineHierarchy(dm, refine, dms)); 4425 /* Total hack since we do not pass in a pointer */ 4426 PetscCall(DMPlexSwap_Static(dm, dms[refine - 1])); 4427 if (refine == 1) { 4428 PetscCall(DMSetCoarseDM(dm, dms[0])); 4429 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4430 } else { 4431 PetscCall(DMSetCoarseDM(dm, dms[refine - 2])); 4432 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4433 PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1])); 4434 PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE)); 4435 } 4436 PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM)); 4437 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 4438 /* Free DMs */ 4439 for (r = 0; r < refine; ++r) { 4440 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4441 PetscCall(DMDestroy(&dms[r])); 4442 } 4443 PetscCall(PetscFree(dms)); 4444 } else { 4445 for (r = 0; r < refine; ++r) { 4446 DM rdm; 4447 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4448 4449 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4450 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4451 /* Total hack since we do not pass in a pointer */ 4452 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4453 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4454 if (coordFunc && remap) { 4455 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4456 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4457 } 4458 } 4459 } 4460 /* Handle DMPlex coarsening */ 4461 PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0)); 4462 PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0)); 4463 if (coarsen && isHierarchy) { 4464 DM *dms; 4465 4466 PetscCall(PetscMalloc1(coarsen, &dms)); 4467 PetscCall(DMCoarsenHierarchy(dm, coarsen, dms)); 4468 /* Free DMs */ 4469 for (r = 0; r < coarsen; ++r) { 4470 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4471 PetscCall(DMDestroy(&dms[r])); 4472 } 4473 PetscCall(PetscFree(dms)); 4474 } else { 4475 for (r = 0; r < coarsen; ++r) { 4476 DM cdm; 4477 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4478 4479 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4480 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm)); 4481 /* Total hack since we do not pass in a pointer */ 4482 PetscCall(DMPlexReplace_Internal(dm, &cdm)); 4483 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4484 if (coordFunc) { 4485 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4486 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4487 } 4488 } 4489 } 4490 // Handle coordinate remapping 4491 remap = PETSC_FALSE; 4492 PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL)); 4493 if (remap) { 4494 DMPlexCoordMap map = DM_COORD_MAP_NONE; 4495 PetscPointFunc mapFunc = NULL; 4496 PetscScalar params[16]; 4497 PetscInt Np = sizeof(params) / sizeof(params[0]), cdim; 4498 MPI_Comm comm; 4499 4500 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4501 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4502 PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg)); 4503 if (!flg) Np = 0; 4504 // TODO Allow user to pass a map function by name 4505 PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg)); 4506 if (flg) { 4507 switch (map) { 4508 case DM_COORD_MAP_NONE: 4509 mapFunc = coordMap_identity; 4510 break; 4511 case DM_COORD_MAP_SHEAR: 4512 mapFunc = coordMap_shear; 4513 if (!Np) { 4514 Np = cdim + 1; 4515 params[0] = 0; 4516 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 4517 } 4518 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); 4519 break; 4520 case DM_COORD_MAP_FLARE: 4521 mapFunc = coordMap_flare; 4522 if (!Np) { 4523 Np = cdim + 1; 4524 params[0] = 0; 4525 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 4526 } 4527 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); 4528 break; 4529 case DM_COORD_MAP_ANNULUS: 4530 mapFunc = coordMap_annulus; 4531 if (!Np) { 4532 Np = 2; 4533 params[0] = 1.; 4534 params[1] = 2.; 4535 } 4536 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 4537 break; 4538 case DM_COORD_MAP_SHELL: 4539 mapFunc = coordMap_shell; 4540 if (!Np) { 4541 Np = 2; 4542 params[0] = 1.; 4543 params[1] = 2.; 4544 } 4545 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 4546 break; 4547 default: 4548 mapFunc = coordMap_identity; 4549 } 4550 } 4551 if (Np) { 4552 DM cdm; 4553 PetscDS cds; 4554 4555 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4556 PetscCall(DMGetDS(cdm, &cds)); 4557 PetscCall(PetscDSSetConstants(cds, Np, params)); 4558 } 4559 PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc)); 4560 } 4561 /* Handle ghost cells */ 4562 PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL)); 4563 if (ghostCells) { 4564 DM gdm; 4565 char lname[PETSC_MAX_PATH_LEN]; 4566 4567 lname[0] = '\0'; 4568 PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg)); 4569 PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm)); 4570 PetscCall(DMPlexReplace_Internal(dm, &gdm)); 4571 } 4572 /* Handle 1D order */ 4573 if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) { 4574 DM cdm, rdm; 4575 PetscDS cds; 4576 PetscObject obj; 4577 PetscClassId id = PETSC_OBJECT_CLASSID; 4578 IS perm; 4579 PetscInt Nf; 4580 PetscBool distributed; 4581 4582 PetscCall(DMPlexIsDistributed(dm, &distributed)); 4583 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4584 PetscCall(DMGetDS(cdm, &cds)); 4585 PetscCall(PetscDSGetNumFields(cds, &Nf)); 4586 if (Nf) { 4587 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4588 PetscCall(PetscObjectGetClassId(obj, &id)); 4589 } 4590 if (!distributed && id != PETSCFE_CLASSID) { 4591 PetscCall(DMPlexGetOrdering1D(dm, &perm)); 4592 PetscCall(DMPlexPermute(dm, perm, &rdm)); 4593 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4594 PetscCall(ISDestroy(&perm)); 4595 } 4596 } 4597 /* Handle */ 4598 non_refine: 4599 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4600 PetscOptionsHeadEnd(); 4601 PetscFunctionReturn(PETSC_SUCCESS); 4602 } 4603 4604 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec) 4605 { 4606 PetscFunctionBegin; 4607 PetscCall(DMCreateGlobalVector_Section_Private(dm, vec)); 4608 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 4609 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex)); 4610 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native)); 4611 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex)); 4612 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native)); 4613 PetscFunctionReturn(PETSC_SUCCESS); 4614 } 4615 4616 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec) 4617 { 4618 PetscFunctionBegin; 4619 PetscCall(DMCreateLocalVector_Section_Private(dm, vec)); 4620 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local)); 4621 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local)); 4622 PetscFunctionReturn(PETSC_SUCCESS); 4623 } 4624 4625 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 4626 { 4627 PetscInt depth, d; 4628 4629 PetscFunctionBegin; 4630 PetscCall(DMPlexGetDepth(dm, &depth)); 4631 if (depth == 1) { 4632 PetscCall(DMGetDimension(dm, &d)); 4633 if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4634 else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd)); 4635 else { 4636 *pStart = 0; 4637 *pEnd = 0; 4638 } 4639 } else { 4640 PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4641 } 4642 PetscFunctionReturn(PETSC_SUCCESS); 4643 } 4644 4645 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 4646 { 4647 PetscSF sf; 4648 PetscInt niranks, njranks, n; 4649 const PetscMPIInt *iranks, *jranks; 4650 DM_Plex *data = (DM_Plex *)dm->data; 4651 4652 PetscFunctionBegin; 4653 PetscCall(DMGetPointSF(dm, &sf)); 4654 if (!data->neighbors) { 4655 PetscCall(PetscSFSetUp(sf)); 4656 PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL)); 4657 PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL)); 4658 PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors)); 4659 PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks)); 4660 PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks)); 4661 n = njranks + niranks; 4662 PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1)); 4663 /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */ 4664 PetscCall(PetscMPIIntCast(n, data->neighbors)); 4665 } 4666 if (nranks) *nranks = data->neighbors[0]; 4667 if (ranks) { 4668 if (data->neighbors[0]) *ranks = data->neighbors + 1; 4669 else *ranks = NULL; 4670 } 4671 PetscFunctionReturn(PETSC_SUCCESS); 4672 } 4673 4674 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec); 4675 4676 static PetscErrorCode DMInitialize_Plex(DM dm) 4677 { 4678 PetscFunctionBegin; 4679 dm->ops->view = DMView_Plex; 4680 dm->ops->load = DMLoad_Plex; 4681 dm->ops->setfromoptions = DMSetFromOptions_Plex; 4682 dm->ops->clone = DMClone_Plex; 4683 dm->ops->setup = DMSetUp_Plex; 4684 dm->ops->createlocalsection = DMCreateLocalSection_Plex; 4685 dm->ops->createsectionpermutation = DMCreateSectionPermutation_Plex; 4686 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_Plex; 4687 dm->ops->createglobalvector = DMCreateGlobalVector_Plex; 4688 dm->ops->createlocalvector = DMCreateLocalVector_Plex; 4689 dm->ops->getlocaltoglobalmapping = NULL; 4690 dm->ops->createfieldis = NULL; 4691 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Plex; 4692 dm->ops->createcoordinatefield = DMCreateCoordinateField_Plex; 4693 dm->ops->getcoloring = NULL; 4694 dm->ops->creatematrix = DMCreateMatrix_Plex; 4695 dm->ops->createinterpolation = DMCreateInterpolation_Plex; 4696 dm->ops->createmassmatrix = DMCreateMassMatrix_Plex; 4697 dm->ops->createmassmatrixlumped = DMCreateMassMatrixLumped_Plex; 4698 dm->ops->createinjection = DMCreateInjection_Plex; 4699 dm->ops->refine = DMRefine_Plex; 4700 dm->ops->coarsen = DMCoarsen_Plex; 4701 dm->ops->refinehierarchy = DMRefineHierarchy_Plex; 4702 dm->ops->coarsenhierarchy = DMCoarsenHierarchy_Plex; 4703 dm->ops->extrude = DMExtrude_Plex; 4704 dm->ops->globaltolocalbegin = NULL; 4705 dm->ops->globaltolocalend = NULL; 4706 dm->ops->localtoglobalbegin = NULL; 4707 dm->ops->localtoglobalend = NULL; 4708 dm->ops->destroy = DMDestroy_Plex; 4709 dm->ops->createsubdm = DMCreateSubDM_Plex; 4710 dm->ops->createsuperdm = DMCreateSuperDM_Plex; 4711 dm->ops->getdimpoints = DMGetDimPoints_Plex; 4712 dm->ops->locatepoints = DMLocatePoints_Plex; 4713 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_Plex; 4714 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex; 4715 dm->ops->projectfieldlocal = DMProjectFieldLocal_Plex; 4716 dm->ops->projectfieldlabellocal = DMProjectFieldLabelLocal_Plex; 4717 dm->ops->projectbdfieldlabellocal = DMProjectBdFieldLabelLocal_Plex; 4718 dm->ops->computel2diff = DMComputeL2Diff_Plex; 4719 dm->ops->computel2gradientdiff = DMComputeL2GradientDiff_Plex; 4720 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_Plex; 4721 dm->ops->getneighbors = DMGetNeighbors_Plex; 4722 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex; 4723 dm->ops->createddscatters = DMCreateDomainDecompositionScatters_Plex; 4724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex)); 4725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex)); 4726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex)); 4727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex)); 4728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex)); 4729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex)); 4730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex)); 4731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex)); 4732 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex)); 4733 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex)); 4734 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex)); 4735 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex)); 4736 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex)); 4737 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 4738 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex)); 4739 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex)); 4740 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex)); 4741 PetscFunctionReturn(PETSC_SUCCESS); 4742 } 4743 4744 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm) 4745 { 4746 DM_Plex *mesh = (DM_Plex *)dm->data; 4747 PetscSF face_sf; 4748 4749 PetscFunctionBegin; 4750 mesh->refct++; 4751 (*newdm)->data = mesh; 4752 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &face_sf)); 4753 PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, face_sf)); 4754 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX)); 4755 PetscCall(DMInitialize_Plex(*newdm)); 4756 PetscFunctionReturn(PETSC_SUCCESS); 4757 } 4758 4759 /*MC 4760 DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram. 4761 In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is 4762 specified by a PetscSection object. Ownership in the global representation is determined by 4763 ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object. 4764 4765 Options Database Keys: 4766 + -dm_refine_pre - Refine mesh before distribution 4767 + -dm_refine_uniform_pre - Choose uniform or generator-based refinement 4768 + -dm_refine_volume_limit_pre - Cell volume limit after pre-refinement using generator 4769 . -dm_distribute - Distribute mesh across processes 4770 . -dm_distribute_overlap - Number of cells to overlap for distribution 4771 . -dm_refine - Refine mesh after distribution 4772 . -dm_plex_hash_location - Use grid hashing for point location 4773 . -dm_plex_hash_box_faces <n,m,p> - The number of divisions in each direction of the grid hash 4774 . -dm_plex_partition_balance - Attempt to evenly divide points on partition boundary between processes 4775 . -dm_plex_remesh_bd - Allow changes to the boundary on remeshing 4776 . -dm_plex_max_projection_height - Maximum mesh point height used to project locally 4777 . -dm_plex_regular_refinement - Use special nested projection algorithm for regular refinement 4778 . -dm_plex_reorder_section - Use specialized blocking if available 4779 . -dm_plex_check_all - Perform all checks below 4780 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric 4781 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices 4782 . -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 4783 . -dm_plex_check_geometry - Check that cells have positive volume 4784 . -dm_view :mesh.tex:ascii_latex - View the mesh in LaTeX/TikZ 4785 . -dm_plex_view_scale <num> - Scale the TikZ 4786 . -dm_plex_print_fem <num> - View FEM assembly information, such as element vectors and matrices 4787 - -dm_plex_print_fvm <num> - View FVM assembly information, such as flux updates 4788 4789 Level: intermediate 4790 4791 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection` 4792 M*/ 4793 4794 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm) 4795 { 4796 DM_Plex *mesh; 4797 PetscInt unit; 4798 4799 PetscFunctionBegin; 4800 PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite)); 4801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4802 PetscCall(PetscNew(&mesh)); 4803 dm->reorderSection = DM_REORDER_DEFAULT_NOTSET; 4804 dm->data = mesh; 4805 4806 mesh->refct = 1; 4807 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection)); 4808 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection)); 4809 mesh->refinementUniform = PETSC_TRUE; 4810 mesh->refinementLimit = -1.0; 4811 mesh->distDefault = PETSC_TRUE; 4812 mesh->reorderDefault = DM_REORDER_DEFAULT_NOTSET; 4813 mesh->distributionName = NULL; 4814 mesh->interpolated = DMPLEX_INTERPOLATED_INVALID; 4815 mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID; 4816 4817 PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner)); 4818 mesh->remeshBd = PETSC_FALSE; 4819 4820 for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0; 4821 4822 mesh->depthState = -1; 4823 mesh->celltypeState = -1; 4824 mesh->printTol = 1.0e-10; 4825 4826 PetscCall(DMInitialize_Plex(dm)); 4827 PetscFunctionReturn(PETSC_SUCCESS); 4828 } 4829 4830 /*@ 4831 DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram. 4832 4833 Collective 4834 4835 Input Parameter: 4836 . comm - The communicator for the `DMPLEX` object 4837 4838 Output Parameter: 4839 . mesh - The `DMPLEX` object 4840 4841 Level: beginner 4842 4843 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()` 4844 @*/ 4845 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh) 4846 { 4847 PetscFunctionBegin; 4848 PetscAssertPointer(mesh, 2); 4849 PetscCall(DMCreate(comm, mesh)); 4850 PetscCall(DMSetType(*mesh, DMPLEX)); 4851 PetscFunctionReturn(PETSC_SUCCESS); 4852 } 4853 4854 /*@C 4855 DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 4856 4857 Collective; No Fortran Support 4858 4859 Input Parameters: 4860 + dm - The `DM` 4861 . numCells - The number of cells owned by this process 4862 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 4863 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 4864 . numCorners - The number of vertices for each cell 4865 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 4866 4867 Output Parameters: 4868 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 4869 - verticesAdjSaved - (Optional) vertex adjacency array 4870 4871 Level: advanced 4872 4873 Notes: 4874 Two triangles sharing a face 4875 .vb 4876 4877 2 4878 / | \ 4879 / | \ 4880 / | \ 4881 0 0 | 1 3 4882 \ | / 4883 \ | / 4884 \ | / 4885 1 4886 .ve 4887 would have input 4888 .vb 4889 numCells = 2, numVertices = 4 4890 cells = [0 1 2 1 3 2] 4891 .ve 4892 which would result in the `DMPLEX` 4893 .vb 4894 4895 4 4896 / | \ 4897 / | \ 4898 / | \ 4899 2 0 | 1 5 4900 \ | / 4901 \ | / 4902 \ | / 4903 3 4904 .ve 4905 4906 Vertices are implicitly numbered consecutively 0,...,NVertices. 4907 Each rank owns a chunk of numVertices consecutive vertices. 4908 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 4909 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 4910 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 4911 4912 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 4913 4914 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 4915 `PetscSF` 4916 @*/ 4917 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved) 4918 { 4919 PetscSF sfPoint; 4920 PetscLayout layout; 4921 PetscInt numVerticesAdj, *verticesAdj, *cones, c, p; 4922 4923 PetscFunctionBegin; 4924 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 4925 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 4926 /* Get/check global number of vertices */ 4927 { 4928 PetscInt NVerticesInCells, i; 4929 const PetscInt len = numCells * numCorners; 4930 4931 /* NVerticesInCells = max(cells) + 1 */ 4932 NVerticesInCells = PETSC_MIN_INT; 4933 for (i = 0; i < len; i++) 4934 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 4935 ++NVerticesInCells; 4936 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4937 4938 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 4939 else 4940 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); 4941 } 4942 /* Count locally unique vertices */ 4943 { 4944 PetscHSetI vhash; 4945 PetscInt off = 0; 4946 4947 PetscCall(PetscHSetICreate(&vhash)); 4948 for (c = 0; c < numCells; ++c) { 4949 for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p])); 4950 } 4951 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 4952 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 4953 else verticesAdj = *verticesAdjSaved; 4954 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 4955 PetscCall(PetscHSetIDestroy(&vhash)); 4956 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 4957 } 4958 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 4959 /* Create cones */ 4960 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 4961 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 4962 PetscCall(DMSetUp(dm)); 4963 PetscCall(DMPlexGetCones(dm, &cones)); 4964 for (c = 0; c < numCells; ++c) { 4965 for (p = 0; p < numCorners; ++p) { 4966 const PetscInt gv = cells[c * numCorners + p]; 4967 PetscInt lv; 4968 4969 /* Positions within verticesAdj form 0-based local vertex numbering; 4970 we need to shift it by numCells to get correct DAG points (cells go first) */ 4971 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 4972 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 4973 cones[c * numCorners + p] = lv + numCells; 4974 } 4975 } 4976 /* Build point sf */ 4977 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 4978 PetscCall(PetscLayoutSetSize(layout, NVertices)); 4979 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 4980 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 4981 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 4982 PetscCall(PetscLayoutDestroy(&layout)); 4983 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 4984 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 4985 if (dm->sf) { 4986 const char *prefix; 4987 4988 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 4989 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 4990 } 4991 PetscCall(DMSetPointSF(dm, sfPoint)); 4992 PetscCall(PetscSFDestroy(&sfPoint)); 4993 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)(*vertexSF), "Vertex Ownership SF")); 4994 /* Fill in the rest of the topology structure */ 4995 PetscCall(DMPlexSymmetrize(dm)); 4996 PetscCall(DMPlexStratify(dm)); 4997 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 4998 PetscFunctionReturn(PETSC_SUCCESS); 4999 } 5000 5001 /*@C 5002 DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 5003 5004 Collective; No Fortran Support 5005 5006 Input Parameters: 5007 + dm - The `DM` 5008 . spaceDim - The spatial dimension used for coordinates 5009 . sfVert - `PetscSF` describing complete vertex ownership 5010 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5011 5012 Level: advanced 5013 5014 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()` 5015 @*/ 5016 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[]) 5017 { 5018 PetscSection coordSection; 5019 Vec coordinates; 5020 PetscScalar *coords; 5021 PetscInt numVertices, numVerticesAdj, coordSize, v, vStart, vEnd; 5022 5023 PetscFunctionBegin; 5024 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5025 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 5026 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 5027 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 5028 PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL)); 5029 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); 5030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5031 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5032 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 5033 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 5034 for (v = vStart; v < vEnd; ++v) { 5035 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 5036 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 5037 } 5038 PetscCall(PetscSectionSetUp(coordSection)); 5039 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5040 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates)); 5041 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 5042 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5043 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5044 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5045 PetscCall(VecGetArray(coordinates, &coords)); 5046 { 5047 MPI_Datatype coordtype; 5048 5049 /* Need a temp buffer for coords if we have complex/single */ 5050 PetscCallMPI(MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype)); 5051 PetscCallMPI(MPI_Type_commit(&coordtype)); 5052 #if defined(PETSC_USE_COMPLEX) 5053 { 5054 PetscScalar *svertexCoords; 5055 PetscInt i; 5056 PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords)); 5057 for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i]; 5058 PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 5059 PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 5060 PetscCall(PetscFree(svertexCoords)); 5061 } 5062 #else 5063 PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 5064 PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 5065 #endif 5066 PetscCallMPI(MPI_Type_free(&coordtype)); 5067 } 5068 PetscCall(VecRestoreArray(coordinates, &coords)); 5069 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5070 PetscCall(VecDestroy(&coordinates)); 5071 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5072 PetscFunctionReturn(PETSC_SUCCESS); 5073 } 5074 5075 /*@ 5076 DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) 5077 5078 Collective 5079 5080 Input Parameters: 5081 + comm - The communicator 5082 . dim - The topological dimension of the mesh 5083 . numCells - The number of cells owned by this process 5084 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 5085 . NVertices - The global number of vertices, or `PETSC_DECIDE` 5086 . numCorners - The number of vertices for each cell 5087 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5088 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5089 . spaceDim - The spatial dimension used for coordinates 5090 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5091 5092 Output Parameters: 5093 + dm - The `DM` 5094 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5095 - verticesAdj - (Optional) vertex adjacency array 5096 5097 Level: intermediate 5098 5099 Notes: 5100 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 5101 `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 5102 5103 See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters. 5104 5105 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 5106 5107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5108 @*/ 5109 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) 5110 { 5111 PetscSF sfVert; 5112 5113 PetscFunctionBegin; 5114 PetscCall(DMCreate(comm, dm)); 5115 PetscCall(DMSetType(*dm, DMPLEX)); 5116 PetscValidLogicalCollectiveInt(*dm, dim, 2); 5117 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 5118 PetscCall(DMSetDimension(*dm, dim)); 5119 PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj)); 5120 if (interpolate) { 5121 DM idm; 5122 5123 PetscCall(DMPlexInterpolate(*dm, &idm)); 5124 PetscCall(DMDestroy(dm)); 5125 *dm = idm; 5126 } 5127 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 5128 if (vertexSF) *vertexSF = sfVert; 5129 else PetscCall(PetscSFDestroy(&sfVert)); 5130 PetscFunctionReturn(PETSC_SUCCESS); 5131 } 5132 5133 /*@C 5134 DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 5135 5136 Collective; No Fortran Support 5137 5138 Input Parameters: 5139 + dm - The `DM` 5140 . numCells - The number of cells owned by this process 5141 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE` 5142 . numCorners - The number of vertices for each cell 5143 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5144 5145 Level: advanced 5146 5147 Notes: 5148 Two triangles sharing a face 5149 .vb 5150 5151 2 5152 / | \ 5153 / | \ 5154 / | \ 5155 0 0 | 1 3 5156 \ | / 5157 \ | / 5158 \ | / 5159 1 5160 .ve 5161 would have input 5162 .vb 5163 numCells = 2, numVertices = 4 5164 cells = [0 1 2 1 3 2] 5165 .ve 5166 which would result in the `DMPLEX` 5167 .vb 5168 5169 4 5170 / | \ 5171 / | \ 5172 / | \ 5173 2 0 | 1 5 5174 \ | / 5175 \ | / 5176 \ | / 5177 3 5178 .ve 5179 5180 If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1. 5181 5182 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()` 5183 @*/ 5184 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[]) 5185 { 5186 PetscInt *cones, c, p, dim; 5187 5188 PetscFunctionBegin; 5189 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5190 PetscCall(DMGetDimension(dm, &dim)); 5191 /* Get/check global number of vertices */ 5192 { 5193 PetscInt NVerticesInCells, i; 5194 const PetscInt len = numCells * numCorners; 5195 5196 /* NVerticesInCells = max(cells) + 1 */ 5197 NVerticesInCells = PETSC_MIN_INT; 5198 for (i = 0; i < len; i++) 5199 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5200 ++NVerticesInCells; 5201 5202 if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells; 5203 else 5204 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); 5205 } 5206 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 5207 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5208 PetscCall(DMSetUp(dm)); 5209 PetscCall(DMPlexGetCones(dm, &cones)); 5210 for (c = 0; c < numCells; ++c) { 5211 for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells; 5212 } 5213 PetscCall(DMPlexSymmetrize(dm)); 5214 PetscCall(DMPlexStratify(dm)); 5215 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5216 PetscFunctionReturn(PETSC_SUCCESS); 5217 } 5218 5219 /*@C 5220 DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 5221 5222 Collective; No Fortran Support 5223 5224 Input Parameters: 5225 + dm - The `DM` 5226 . spaceDim - The spatial dimension used for coordinates 5227 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5228 5229 Level: advanced 5230 5231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()` 5232 @*/ 5233 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[]) 5234 { 5235 PetscSection coordSection; 5236 Vec coordinates; 5237 DM cdm; 5238 PetscScalar *coords; 5239 PetscInt v, vStart, vEnd, d; 5240 5241 PetscFunctionBegin; 5242 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5243 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 5244 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 5245 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 5246 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5247 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5248 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 5249 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 5250 for (v = vStart; v < vEnd; ++v) { 5251 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 5252 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 5253 } 5254 PetscCall(PetscSectionSetUp(coordSection)); 5255 5256 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5257 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 5258 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 5259 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5260 PetscCall(VecGetArrayWrite(coordinates, &coords)); 5261 for (v = 0; v < vEnd - vStart; ++v) { 5262 for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d]; 5263 } 5264 PetscCall(VecRestoreArrayWrite(coordinates, &coords)); 5265 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5266 PetscCall(VecDestroy(&coordinates)); 5267 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5268 PetscFunctionReturn(PETSC_SUCCESS); 5269 } 5270 5271 /*@ 5272 DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input 5273 5274 Collective 5275 5276 Input Parameters: 5277 + comm - The communicator 5278 . dim - The topological dimension of the mesh 5279 . numCells - The number of cells, only on process 0 5280 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0 5281 . numCorners - The number of vertices for each cell, only on process 0 5282 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5283 . cells - An array of numCells*numCorners numbers, the vertices for each cell, only on process 0 5284 . spaceDim - The spatial dimension used for coordinates 5285 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex, only on process 0 5286 5287 Output Parameter: 5288 . dm - The `DM`, which only has points on process 0 5289 5290 Level: intermediate 5291 5292 Notes: 5293 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`, 5294 `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()` 5295 5296 See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters. 5297 See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters. 5298 See `DMPlexCreateFromCellListParallelPetsc()` for parallel input 5299 5300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5301 @*/ 5302 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) 5303 { 5304 PetscMPIInt rank; 5305 5306 PetscFunctionBegin; 5307 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."); 5308 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5309 PetscCall(DMCreate(comm, dm)); 5310 PetscCall(DMSetType(*dm, DMPLEX)); 5311 PetscCall(DMSetDimension(*dm, dim)); 5312 if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells)); 5313 else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL)); 5314 if (interpolate) { 5315 DM idm; 5316 5317 PetscCall(DMPlexInterpolate(*dm, &idm)); 5318 PetscCall(DMDestroy(dm)); 5319 *dm = idm; 5320 } 5321 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords)); 5322 else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL)); 5323 PetscFunctionReturn(PETSC_SUCCESS); 5324 } 5325 5326 /*@ 5327 DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM` 5328 5329 Input Parameters: 5330 + dm - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()` 5331 . depth - The depth of the DAG 5332 . numPoints - Array of size depth + 1 containing the number of points at each `depth` 5333 . coneSize - The cone size of each point 5334 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point 5335 . coneOrientations - The orientation of each cone point 5336 - vertexCoords - An array of `numPoints`[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via `DMSetCoordinateDim()` 5337 5338 Output Parameter: 5339 . dm - The `DM` 5340 5341 Level: advanced 5342 5343 Note: 5344 Two triangles sharing a face would have input 5345 .vb 5346 depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0] 5347 cones = [2 3 4 3 5 4], coneOrientations = [0 0 0 0 0 0] 5348 vertexCoords = [-1.0 0.0 0.0 -1.0 0.0 1.0 1.0 0.0] 5349 .ve 5350 which would result in the DMPlex 5351 .vb 5352 4 5353 / | \ 5354 / | \ 5355 / | \ 5356 2 0 | 1 5 5357 \ | / 5358 \ | / 5359 \ | / 5360 3 5361 .ve 5362 Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()` 5363 5364 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 5365 @*/ 5366 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[]) 5367 { 5368 Vec coordinates; 5369 PetscSection coordSection; 5370 PetscScalar *coords; 5371 PetscInt coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off; 5372 5373 PetscFunctionBegin; 5374 PetscCall(DMGetDimension(dm, &dim)); 5375 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 5376 PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim); 5377 for (d = 0; d <= depth; ++d) pEnd += numPoints[d]; 5378 PetscCall(DMPlexSetChart(dm, pStart, pEnd)); 5379 for (p = pStart; p < pEnd; ++p) { 5380 PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart])); 5381 if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart; 5382 } 5383 PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]); 5384 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 5385 for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) { 5386 PetscCall(DMPlexSetCone(dm, p, &cones[off])); 5387 PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off])); 5388 } 5389 PetscCall(DMPlexSymmetrize(dm)); 5390 PetscCall(DMPlexStratify(dm)); 5391 /* Build coordinates */ 5392 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5393 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5394 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed)); 5395 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0])); 5396 for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) { 5397 PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed)); 5398 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed)); 5399 } 5400 PetscCall(PetscSectionSetUp(coordSection)); 5401 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5402 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 5403 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5404 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5405 PetscCall(VecSetBlockSize(coordinates, dimEmbed)); 5406 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5407 if (vertexCoords) { 5408 PetscCall(VecGetArray(coordinates, &coords)); 5409 for (v = 0; v < numPoints[0]; ++v) { 5410 PetscInt off; 5411 5412 PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off)); 5413 for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d]; 5414 } 5415 } 5416 PetscCall(VecRestoreArray(coordinates, &coords)); 5417 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5418 PetscCall(VecDestroy(&coordinates)); 5419 PetscFunctionReturn(PETSC_SUCCESS); 5420 } 5421 5422 /* 5423 DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file. 5424 5425 Collective 5426 5427 + comm - The MPI communicator 5428 . filename - Name of the .dat file 5429 - interpolate - Create faces and edges in the mesh 5430 5431 Output Parameter: 5432 . dm - The `DM` object representing the mesh 5433 5434 Level: beginner 5435 5436 Note: 5437 The format is the simplest possible: 5438 .vb 5439 Ne 5440 v0 v1 ... vk 5441 Nv 5442 x y z marker 5443 .ve 5444 5445 Developer Note: 5446 Should use a `PetscViewer` not a filename 5447 5448 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()` 5449 */ 5450 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 5451 { 5452 DMLabel marker; 5453 PetscViewer viewer; 5454 Vec coordinates; 5455 PetscSection coordSection; 5456 PetscScalar *coords; 5457 char line[PETSC_MAX_PATH_LEN]; 5458 PetscInt dim = 3, cdim = 3, coordSize, v, c, d; 5459 PetscMPIInt rank; 5460 int snum, Nv, Nc, Ncn, Nl; 5461 5462 PetscFunctionBegin; 5463 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5464 PetscCall(PetscViewerCreate(comm, &viewer)); 5465 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII)); 5466 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 5467 PetscCall(PetscViewerFileSetName(viewer, filename)); 5468 if (rank == 0) { 5469 PetscCall(PetscViewerRead(viewer, line, 4, NULL, PETSC_STRING)); 5470 snum = sscanf(line, "%d %d %d %d", &Nc, &Nv, &Ncn, &Nl); 5471 PetscCheck(snum == 4, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5472 } else { 5473 Nc = Nv = Ncn = Nl = 0; 5474 } 5475 PetscCall(DMCreate(comm, dm)); 5476 PetscCall(DMSetType(*dm, DMPLEX)); 5477 PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv)); 5478 PetscCall(DMSetDimension(*dm, dim)); 5479 PetscCall(DMSetCoordinateDim(*dm, cdim)); 5480 /* Read topology */ 5481 if (rank == 0) { 5482 char format[PETSC_MAX_PATH_LEN]; 5483 PetscInt cone[8]; 5484 int vbuf[8], v; 5485 5486 for (c = 0; c < Ncn; ++c) { 5487 format[c * 3 + 0] = '%'; 5488 format[c * 3 + 1] = 'd'; 5489 format[c * 3 + 2] = ' '; 5490 } 5491 format[Ncn * 3 - 1] = '\0'; 5492 for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn)); 5493 PetscCall(DMSetUp(*dm)); 5494 for (c = 0; c < Nc; ++c) { 5495 PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING)); 5496 switch (Ncn) { 5497 case 2: 5498 snum = sscanf(line, format, &vbuf[0], &vbuf[1]); 5499 break; 5500 case 3: 5501 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]); 5502 break; 5503 case 4: 5504 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]); 5505 break; 5506 case 6: 5507 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]); 5508 break; 5509 case 8: 5510 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]); 5511 break; 5512 default: 5513 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn); 5514 } 5515 PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5516 for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc; 5517 /* Hexahedra are inverted */ 5518 if (Ncn == 8) { 5519 PetscInt tmp = cone[1]; 5520 cone[1] = cone[3]; 5521 cone[3] = tmp; 5522 } 5523 PetscCall(DMPlexSetCone(*dm, c, cone)); 5524 } 5525 } 5526 PetscCall(DMPlexSymmetrize(*dm)); 5527 PetscCall(DMPlexStratify(*dm)); 5528 /* Read coordinates */ 5529 PetscCall(DMGetCoordinateSection(*dm, &coordSection)); 5530 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5531 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 5532 PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv)); 5533 for (v = Nc; v < Nc + Nv; ++v) { 5534 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 5535 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 5536 } 5537 PetscCall(PetscSectionSetUp(coordSection)); 5538 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5539 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 5540 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5541 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5542 PetscCall(VecSetBlockSize(coordinates, cdim)); 5543 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5544 PetscCall(VecGetArray(coordinates, &coords)); 5545 if (rank == 0) { 5546 char format[PETSC_MAX_PATH_LEN]; 5547 double x[3]; 5548 int l, val[3]; 5549 5550 if (Nl) { 5551 for (l = 0; l < Nl; ++l) { 5552 format[l * 3 + 0] = '%'; 5553 format[l * 3 + 1] = 'd'; 5554 format[l * 3 + 2] = ' '; 5555 } 5556 format[Nl * 3 - 1] = '\0'; 5557 PetscCall(DMCreateLabel(*dm, "marker")); 5558 PetscCall(DMGetLabel(*dm, "marker", &marker)); 5559 } 5560 for (v = 0; v < Nv; ++v) { 5561 PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING)); 5562 snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]); 5563 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5564 switch (Nl) { 5565 case 0: 5566 snum = 0; 5567 break; 5568 case 1: 5569 snum = sscanf(line, format, &val[0]); 5570 break; 5571 case 2: 5572 snum = sscanf(line, format, &val[0], &val[1]); 5573 break; 5574 case 3: 5575 snum = sscanf(line, format, &val[0], &val[1], &val[2]); 5576 break; 5577 default: 5578 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl); 5579 } 5580 PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5581 for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d]; 5582 for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l])); 5583 } 5584 } 5585 PetscCall(VecRestoreArray(coordinates, &coords)); 5586 PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 5587 PetscCall(VecDestroy(&coordinates)); 5588 PetscCall(PetscViewerDestroy(&viewer)); 5589 if (interpolate) { 5590 DM idm; 5591 DMLabel bdlabel; 5592 5593 PetscCall(DMPlexInterpolate(*dm, &idm)); 5594 PetscCall(DMDestroy(dm)); 5595 *dm = idm; 5596 5597 if (!Nl) { 5598 PetscCall(DMCreateLabel(*dm, "marker")); 5599 PetscCall(DMGetLabel(*dm, "marker", &bdlabel)); 5600 PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel)); 5601 PetscCall(DMPlexLabelComplete(*dm, bdlabel)); 5602 } 5603 } 5604 PetscFunctionReturn(PETSC_SUCCESS); 5605 } 5606 5607 /*@C 5608 DMPlexCreateFromFile - This takes a filename and produces a `DM` 5609 5610 Collective 5611 5612 Input Parameters: 5613 + comm - The communicator 5614 . filename - A file name 5615 . plexname - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats 5616 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 5617 5618 Output Parameter: 5619 . dm - The `DM` 5620 5621 Options Database Key: 5622 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5 5623 5624 Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. 5625 $ -dm_plex_create_viewer_hdf5_collective 5626 5627 Level: beginner 5628 5629 Notes: 5630 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 5631 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 5632 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 5633 The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally 5634 calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats. 5635 5636 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()` 5637 @*/ 5638 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm) 5639 { 5640 const char extGmsh[] = ".msh"; 5641 const char extGmsh2[] = ".msh2"; 5642 const char extGmsh4[] = ".msh4"; 5643 const char extCGNS[] = ".cgns"; 5644 const char extExodus[] = ".exo"; 5645 const char extExodus_e[] = ".e"; 5646 const char extGenesis[] = ".gen"; 5647 const char extFluent[] = ".cas"; 5648 const char extHDF5[] = ".h5"; 5649 const char extXDMFHDF5[] = ".xdmf.h5"; 5650 const char extPLY[] = ".ply"; 5651 const char extEGADSLite[] = ".egadslite"; 5652 const char extEGADS[] = ".egads"; 5653 const char extIGES[] = ".igs"; 5654 const char extSTEP[] = ".stp"; 5655 const char extCV[] = ".dat"; 5656 size_t len; 5657 PetscBool isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSLite, isEGADS, isIGES, isSTEP, isCV, isXDMFHDF5; 5658 PetscMPIInt rank; 5659 5660 PetscFunctionBegin; 5661 PetscAssertPointer(filename, 2); 5662 if (plexname) PetscAssertPointer(plexname, 3); 5663 PetscAssertPointer(dm, 5); 5664 PetscCall(DMInitializePackage()); 5665 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 5666 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5667 PetscCall(PetscStrlen(filename, &len)); 5668 PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path"); 5669 5670 #define CheckExtension(extension__, is_extension__) \ 5671 do { \ 5672 PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \ 5673 /* don't count the null-terminator at the end */ \ 5674 const size_t ext_len = sizeof(extension__) - 1; \ 5675 if (len < ext_len) { \ 5676 is_extension__ = PETSC_FALSE; \ 5677 } else { \ 5678 PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \ 5679 } \ 5680 } while (0) 5681 5682 CheckExtension(extGmsh, isGmsh); 5683 CheckExtension(extGmsh2, isGmsh2); 5684 CheckExtension(extGmsh4, isGmsh4); 5685 CheckExtension(extCGNS, isCGNS); 5686 CheckExtension(extExodus, isExodus); 5687 if (!isExodus) CheckExtension(extExodus_e, isExodus); 5688 CheckExtension(extGenesis, isGenesis); 5689 CheckExtension(extFluent, isFluent); 5690 CheckExtension(extHDF5, isHDF5); 5691 CheckExtension(extPLY, isPLY); 5692 CheckExtension(extEGADSLite, isEGADSLite); 5693 CheckExtension(extEGADS, isEGADS); 5694 CheckExtension(extIGES, isIGES); 5695 CheckExtension(extSTEP, isSTEP); 5696 CheckExtension(extCV, isCV); 5697 CheckExtension(extXDMFHDF5, isXDMFHDF5); 5698 5699 #undef CheckExtension 5700 5701 if (isGmsh || isGmsh2 || isGmsh4) { 5702 PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm)); 5703 } else if (isCGNS) { 5704 PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm)); 5705 } else if (isExodus || isGenesis) { 5706 PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm)); 5707 } else if (isFluent) { 5708 PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm)); 5709 } else if (isHDF5) { 5710 PetscViewer viewer; 5711 5712 /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */ 5713 PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL)); 5714 PetscCall(PetscViewerCreate(comm, &viewer)); 5715 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5)); 5716 PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_")); 5717 PetscCall(PetscViewerSetFromOptions(viewer)); 5718 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 5719 PetscCall(PetscViewerFileSetName(viewer, filename)); 5720 5721 PetscCall(DMCreate(comm, dm)); 5722 PetscCall(PetscObjectSetName((PetscObject)(*dm), plexname)); 5723 PetscCall(DMSetType(*dm, DMPLEX)); 5724 if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF)); 5725 PetscCall(DMLoad(*dm, viewer)); 5726 if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer)); 5727 PetscCall(PetscViewerDestroy(&viewer)); 5728 5729 if (interpolate) { 5730 DM idm; 5731 5732 PetscCall(DMPlexInterpolate(*dm, &idm)); 5733 PetscCall(DMDestroy(dm)); 5734 *dm = idm; 5735 } 5736 } else if (isPLY) { 5737 PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm)); 5738 } else if (isEGADSLite || isEGADS || isIGES || isSTEP) { 5739 if (isEGADSLite) PetscCall(DMPlexCreateEGADSLiteFromFile(comm, filename, dm)); 5740 else PetscCall(DMPlexCreateEGADSFromFile(comm, filename, dm)); 5741 if (!interpolate) { 5742 DM udm; 5743 5744 PetscCall(DMPlexUninterpolate(*dm, &udm)); 5745 PetscCall(DMDestroy(dm)); 5746 *dm = udm; 5747 } 5748 } else if (isCV) { 5749 PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm)); 5750 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename); 5751 PetscCall(PetscStrlen(plexname, &len)); 5752 if (len) PetscCall(PetscObjectSetName((PetscObject)(*dm), plexname)); 5753 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 5754 PetscFunctionReturn(PETSC_SUCCESS); 5755 } 5756 5757 /*@C 5758 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. 5759 5760 Input Parameters: 5761 + tr - The `DMPlexTransform` 5762 - prefix - An options prefix, or NULL 5763 5764 Output Parameter: 5765 . dm - The `DM` 5766 5767 Level: beginner 5768 5769 Notes: 5770 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. 5771 5772 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 5773 @*/ 5774 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm) 5775 { 5776 DM bdm, bcdm, cdm; 5777 Vec coordinates, coordinatesNew; 5778 PetscSection cs; 5779 PetscInt dim, cdim, Nl; 5780 5781 PetscFunctionBegin; 5782 PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm)); 5783 PetscCall(DMSetType(*dm, DMPLEX)); 5784 ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL; 5785 // Handle coordinates 5786 PetscCall(DMPlexTransformGetDM(tr, &bdm)); 5787 PetscCall(DMGetCoordinateDim(bdm, &cdim)); 5788 PetscCall(DMSetCoordinateDim(*dm, cdim)); 5789 PetscCall(DMGetDimension(bdm, &dim)); 5790 PetscCall(DMSetDimension(*dm, dim)); 5791 PetscCall(DMGetCoordinateDM(bdm, &bcdm)); 5792 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 5793 PetscCall(DMCopyDisc(bcdm, cdm)); 5794 PetscCall(DMGetLocalSection(cdm, &cs)); 5795 PetscCall(PetscSectionSetNumFields(cs, 1)); 5796 PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim)); 5797 PetscCall(DMGetCoordinatesLocal(bdm, &coordinates)); 5798 PetscCall(VecDuplicate(coordinates, &coordinatesNew)); 5799 PetscCall(VecCopy(coordinates, coordinatesNew)); 5800 PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew)); 5801 PetscCall(VecDestroy(&coordinatesNew)); 5802 5803 PetscCall(PetscObjectReference((PetscObject)tr)); 5804 PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr)); 5805 ((DM_Plex *)(*dm)->data)->tr = tr; 5806 PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE)); 5807 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix)); 5808 PetscCall(DMSetFromOptions(*dm)); 5809 5810 PetscCall(DMGetNumLabels(bdm, &Nl)); 5811 for (PetscInt l = 0; l < Nl; ++l) { 5812 DMLabel label, labelNew; 5813 const char *lname; 5814 PetscBool isDepth, isCellType; 5815 5816 PetscCall(DMGetLabelName(bdm, l, &lname)); 5817 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 5818 if (isDepth) continue; 5819 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 5820 if (isCellType) continue; 5821 PetscCall(DMCreateLabel(*dm, lname)); 5822 PetscCall(DMGetLabel(bdm, lname, &label)); 5823 PetscCall(DMGetLabel(*dm, lname, &labelNew)); 5824 PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL)); 5825 PetscCall(DMLabelEphemeralSetLabel(labelNew, label)); 5826 PetscCall(DMLabelEphemeralSetTransform(labelNew, tr)); 5827 PetscCall(DMLabelSetUp(labelNew)); 5828 } 5829 PetscFunctionReturn(PETSC_SUCCESS); 5830 } 5831