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