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