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