1 #define PETSCDM_DLL 2 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 3 #include <petsc/private/hashseti.h> /*I "petscdmplex.h" I*/ 4 #include <petscsf.h> 5 #include <petscdmplextransform.h> 6 #include <petscdmlabelephemeral.h> 7 #include <petsc/private/kernels/blockmatmult.h> 8 #include <petsc/private/kernels/blockinvert.h> 9 10 PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_CreateFromOptions, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList; 11 12 /* External function declarations here */ 13 static PetscErrorCode DMInitialize_Plex(DM dm); 14 15 /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */ 16 PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout) 17 { 18 const PetscReal *maxCell, *Lstart, *L; 19 VecType vecType; 20 MatType matType; 21 PetscBool dist, useCeed; 22 DMPlexReorderDefaultFlag reorder; 23 24 PetscFunctionBegin; 25 PetscCall(DMGetVecType(dmin, &vecType)); 26 PetscCall(DMSetVecType(dmout, vecType)); 27 PetscCall(DMGetMatType(dmin, &matType)); 28 PetscCall(DMSetMatType(dmout, matType)); 29 if (copyPeriodicity) { 30 PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L)); 31 PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L)); 32 } 33 PetscCall(DMPlexDistributeGetDefault(dmin, &dist)); 34 PetscCall(DMPlexDistributeSetDefault(dmout, dist)); 35 PetscCall(DMPlexReorderGetDefault(dmin, &reorder)); 36 PetscCall(DMPlexReorderSetDefault(dmout, reorder)); 37 PetscCall(DMPlexGetUseCeed(dmin, &useCeed)); 38 PetscCall(DMPlexSetUseCeed(dmout, useCeed)); 39 ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation; 40 ((DM_Plex *)dmout->data)->printSetValues = ((DM_Plex *)dmin->data)->printSetValues; 41 ((DM_Plex *)dmout->data)->printFEM = ((DM_Plex *)dmin->data)->printFEM; 42 ((DM_Plex *)dmout->data)->printFVM = ((DM_Plex *)dmin->data)->printFVM; 43 ((DM_Plex *)dmout->data)->printL2 = ((DM_Plex *)dmin->data)->printL2; 44 ((DM_Plex *)dmout->data)->printLocate = ((DM_Plex *)dmin->data)->printLocate; 45 ((DM_Plex *)dmout->data)->printTol = ((DM_Plex *)dmin->data)->printTol; 46 if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0)); 47 PetscFunctionReturn(PETSC_SUCCESS); 48 } 49 50 /* Replace dm with the contents of ndm, and then destroy ndm 51 - Share the DM_Plex structure 52 - Share the coordinates 53 - Share the SF 54 */ 55 PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm) 56 { 57 PetscSF sf; 58 DM dmNew = *ndm, coordDM, coarseDM; 59 Vec coords; 60 const PetscReal *maxCell, *Lstart, *L; 61 PetscInt dim, cdim; 62 63 PetscFunctionBegin; 64 if (dm == dmNew) { 65 PetscCall(DMDestroy(ndm)); 66 PetscFunctionReturn(PETSC_SUCCESS); 67 } 68 dm->setupcalled = dmNew->setupcalled; 69 PetscCall(DMGetDimension(dmNew, &dim)); 70 PetscCall(DMSetDimension(dm, dim)); 71 PetscCall(DMGetCoordinateDim(dmNew, &cdim)); 72 PetscCall(DMSetCoordinateDim(dm, cdim)); 73 PetscCall(DMGetPointSF(dmNew, &sf)); 74 PetscCall(DMSetPointSF(dm, sf)); 75 PetscCall(DMGetCoordinateDM(dmNew, &coordDM)); 76 PetscCall(DMGetCoordinatesLocal(dmNew, &coords)); 77 PetscCall(DMSetCoordinateDM(dm, coordDM)); 78 PetscCall(DMSetCoordinatesLocal(dm, coords)); 79 PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM)); 80 PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords)); 81 PetscCall(DMSetCellCoordinateDM(dm, coordDM)); 82 PetscCall(DMSetCellCoordinatesLocal(dm, coords)); 83 /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */ 84 PetscCall(DMFieldDestroy(&dm->coordinates[0].field)); 85 dm->coordinates[0].field = dmNew->coordinates[0].field; 86 ((DM_Plex *)dmNew->data)->coordFunc = ((DM_Plex *)dm->data)->coordFunc; 87 PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L)); 88 PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L)); 89 PetscCall(DMPlexGetGlobalToNaturalSF(dmNew, &sf)); 90 PetscCall(DMPlexSetGlobalToNaturalSF(dm, sf)); 91 PetscCall(DMDestroy_Plex(dm)); 92 PetscCall(DMInitialize_Plex(dm)); 93 dm->data = dmNew->data; 94 ((DM_Plex *)dmNew->data)->refct++; 95 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &sf)); 96 PetscCall(DMPlexSetIsoperiodicFaceSF(dm, sf)); // for the compose function effect on dm 97 PetscCall(DMDestroyLabelLinkList_Internal(dm)); 98 PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL)); 99 PetscCall(DMGetCoarseDM(dmNew, &coarseDM)); 100 PetscCall(DMSetCoarseDM(dm, coarseDM)); 101 PetscCall(DMDestroy(ndm)); 102 PetscFunctionReturn(PETSC_SUCCESS); 103 } 104 105 /* Swap dm with the contents of dmNew 106 - Swap the DM_Plex structure 107 - Swap the coordinates 108 - Swap the point PetscSF 109 */ 110 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB) 111 { 112 DM coordDMA, coordDMB; 113 Vec coordsA, coordsB; 114 PetscSF sfA, sfB; 115 DMField fieldTmp; 116 void *tmp; 117 DMLabelLink listTmp; 118 DMLabel depthTmp; 119 PetscInt tmpI; 120 121 PetscFunctionBegin; 122 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 123 PetscCall(DMGetPointSF(dmA, &sfA)); 124 PetscCall(DMGetPointSF(dmB, &sfB)); 125 PetscCall(PetscObjectReference((PetscObject)sfA)); 126 PetscCall(DMSetPointSF(dmA, sfB)); 127 PetscCall(DMSetPointSF(dmB, sfA)); 128 PetscCall(PetscObjectDereference((PetscObject)sfA)); 129 130 PetscCall(DMGetCoordinateDM(dmA, &coordDMA)); 131 PetscCall(DMGetCoordinateDM(dmB, &coordDMB)); 132 PetscCall(PetscObjectReference((PetscObject)coordDMA)); 133 PetscCall(DMSetCoordinateDM(dmA, coordDMB)); 134 PetscCall(DMSetCoordinateDM(dmB, coordDMA)); 135 PetscCall(PetscObjectDereference((PetscObject)coordDMA)); 136 137 PetscCall(DMGetCoordinatesLocal(dmA, &coordsA)); 138 PetscCall(DMGetCoordinatesLocal(dmB, &coordsB)); 139 PetscCall(PetscObjectReference((PetscObject)coordsA)); 140 PetscCall(DMSetCoordinatesLocal(dmA, coordsB)); 141 PetscCall(DMSetCoordinatesLocal(dmB, coordsA)); 142 PetscCall(PetscObjectDereference((PetscObject)coordsA)); 143 144 PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA)); 145 PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB)); 146 PetscCall(PetscObjectReference((PetscObject)coordDMA)); 147 PetscCall(DMSetCellCoordinateDM(dmA, coordDMB)); 148 PetscCall(DMSetCellCoordinateDM(dmB, coordDMA)); 149 PetscCall(PetscObjectDereference((PetscObject)coordDMA)); 150 151 PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA)); 152 PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB)); 153 PetscCall(PetscObjectReference((PetscObject)coordsA)); 154 PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB)); 155 PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA)); 156 PetscCall(PetscObjectDereference((PetscObject)coordsA)); 157 158 fieldTmp = dmA->coordinates[0].field; 159 dmA->coordinates[0].field = dmB->coordinates[0].field; 160 dmB->coordinates[0].field = fieldTmp; 161 fieldTmp = dmA->coordinates[1].field; 162 dmA->coordinates[1].field = dmB->coordinates[1].field; 163 dmB->coordinates[1].field = fieldTmp; 164 tmp = dmA->data; 165 dmA->data = dmB->data; 166 dmB->data = tmp; 167 listTmp = dmA->labels; 168 dmA->labels = dmB->labels; 169 dmB->labels = listTmp; 170 depthTmp = dmA->depthLabel; 171 dmA->depthLabel = dmB->depthLabel; 172 dmB->depthLabel = depthTmp; 173 depthTmp = dmA->celltypeLabel; 174 dmA->celltypeLabel = dmB->celltypeLabel; 175 dmB->celltypeLabel = depthTmp; 176 tmpI = dmA->levelup; 177 dmA->levelup = dmB->levelup; 178 dmB->levelup = tmpI; 179 PetscFunctionReturn(PETSC_SUCCESS); 180 } 181 182 PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm) 183 { 184 DM idm; 185 186 PetscFunctionBegin; 187 PetscCall(DMPlexInterpolate(dm, &idm)); 188 PetscCall(DMPlexCopyCoordinates(dm, idm)); 189 PetscCall(DMPlexReplace_Internal(dm, &idm)); 190 PetscFunctionReturn(PETSC_SUCCESS); 191 } 192 193 /*@C 194 DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates 195 196 Collective 197 198 Input Parameters: 199 + dm - The `DMPLEX` 200 . degree - The degree of the finite element or `PETSC_DECIDE` 201 . project - Flag to project current coordinates into the space 202 - coordFunc - An optional function to map new points from refinement to the surface 203 204 Level: advanced 205 206 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPointFunc`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()` 207 @*/ 208 PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscBool project, PetscPointFunc coordFunc) 209 { 210 DM_Plex *mesh = (DM_Plex *)dm->data; 211 PetscFE fe = NULL; 212 DM cdm; 213 PetscInt dim, dE, qorder; 214 215 PetscFunctionBegin; 216 PetscCall(DMGetDimension(dm, &dim)); 217 PetscCall(DMGetCoordinateDim(dm, &dE)); 218 qorder = degree; 219 PetscCall(DMGetCoordinateDM(dm, &cdm)); 220 PetscObjectOptionsBegin((PetscObject)cdm); 221 PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0)); 222 PetscOptionsEnd(); 223 if (degree >= 0) { 224 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 225 PetscInt cStart, cEnd, gct; 226 227 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 228 if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 229 gct = (PetscInt)ct; 230 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm))); 231 ct = (DMPolytopeType)gct; 232 // Work around current bug in PetscDualSpaceSetUp_Lagrange() 233 // Can be seen in plex_tutorials-ex10_1 234 if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe)); 235 } 236 PetscCall(DMSetCoordinateDisc(dm, fe, project)); 237 PetscCall(PetscFEDestroy(&fe)); 238 mesh->coordFunc = coordFunc; 239 PetscFunctionReturn(PETSC_SUCCESS); 240 } 241 242 /*@ 243 DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement. 244 245 Collective 246 247 Input Parameters: 248 + comm - The communicator for the `DM` object 249 . dim - The spatial dimension 250 . simplex - Flag for simplicial cells, otherwise they are tensor product cells 251 . interpolate - Flag to create intermediate mesh pieces (edges, faces) 252 - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell 253 254 Output Parameter: 255 . newdm - The `DM` object 256 257 Level: beginner 258 259 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()` 260 @*/ 261 PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm) 262 { 263 DM dm; 264 PetscMPIInt rank; 265 266 PetscFunctionBegin; 267 PetscCall(DMCreate(comm, &dm)); 268 PetscCall(DMSetType(dm, DMPLEX)); 269 PetscCall(DMSetDimension(dm, dim)); 270 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 271 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 272 switch (dim) { 273 case 2: 274 if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular")); 275 else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral")); 276 break; 277 case 3: 278 if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral")); 279 else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral")); 280 break; 281 default: 282 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim); 283 } 284 if (rank) { 285 PetscInt numPoints[2] = {0, 0}; 286 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL)); 287 } else { 288 switch (dim) { 289 case 2: 290 if (simplex) { 291 PetscInt numPoints[2] = {4, 2}; 292 PetscInt coneSize[6] = {3, 3, 0, 0, 0, 0}; 293 PetscInt cones[6] = {2, 3, 4, 5, 4, 3}; 294 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 295 PetscScalar vertexCoords[8] = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5}; 296 297 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 298 } else { 299 PetscInt numPoints[2] = {6, 2}; 300 PetscInt coneSize[8] = {4, 4, 0, 0, 0, 0, 0, 0}; 301 PetscInt cones[8] = {2, 3, 4, 5, 3, 6, 7, 4}; 302 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 303 PetscScalar vertexCoords[12] = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5}; 304 305 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 306 } 307 break; 308 case 3: 309 if (simplex) { 310 PetscInt numPoints[2] = {5, 2}; 311 PetscInt coneSize[7] = {4, 4, 0, 0, 0, 0, 0}; 312 PetscInt cones[8] = {4, 3, 5, 2, 5, 3, 4, 6}; 313 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 314 PetscScalar vertexCoords[15] = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0}; 315 316 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 317 } else { 318 PetscInt numPoints[2] = {12, 2}; 319 PetscInt coneSize[14] = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 320 PetscInt cones[16] = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8}; 321 PetscInt coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 322 PetscScalar vertexCoords[36] = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5}; 323 324 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 325 } 326 break; 327 default: 328 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim); 329 } 330 } 331 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 332 *newdm = dm; 333 if (refinementLimit > 0.0) { 334 DM rdm; 335 const char *name; 336 337 PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE)); 338 PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit)); 339 PetscCall(DMRefine(*newdm, comm, &rdm)); 340 PetscCall(PetscObjectGetName((PetscObject)*newdm, &name)); 341 PetscCall(PetscObjectSetName((PetscObject)rdm, name)); 342 PetscCall(DMDestroy(newdm)); 343 *newdm = rdm; 344 } 345 if (interpolate) { 346 DM idm; 347 348 PetscCall(DMPlexInterpolate(*newdm, &idm)); 349 PetscCall(DMDestroy(newdm)); 350 *newdm = idm; 351 } 352 PetscFunctionReturn(PETSC_SUCCESS); 353 } 354 355 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[]) 356 { 357 const PetscInt numVertices = 2; 358 PetscInt markerRight = 1; 359 PetscInt markerLeft = 1; 360 PetscBool markerSeparate = PETSC_FALSE; 361 Vec coordinates; 362 PetscSection coordSection; 363 PetscScalar *coords; 364 PetscInt coordSize; 365 PetscMPIInt rank; 366 PetscInt cdim = 1, v; 367 368 PetscFunctionBegin; 369 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 370 if (markerSeparate) { 371 markerRight = 2; 372 markerLeft = 1; 373 } 374 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 375 if (rank == 0) { 376 PetscCall(DMPlexSetChart(dm, 0, numVertices)); 377 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 378 PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft)); 379 PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight)); 380 } 381 PetscCall(DMPlexSymmetrize(dm)); 382 PetscCall(DMPlexStratify(dm)); 383 /* Build coordinates */ 384 PetscCall(DMSetCoordinateDim(dm, cdim)); 385 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 386 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 387 PetscCall(PetscSectionSetChart(coordSection, 0, numVertices)); 388 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 389 for (v = 0; v < numVertices; ++v) { 390 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 391 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 392 } 393 PetscCall(PetscSectionSetUp(coordSection)); 394 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 395 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 396 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 397 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 398 PetscCall(VecSetBlockSize(coordinates, cdim)); 399 PetscCall(VecSetType(coordinates, VECSTANDARD)); 400 PetscCall(VecGetArray(coordinates, &coords)); 401 coords[0] = lower[0]; 402 coords[1] = upper[0]; 403 PetscCall(VecRestoreArray(coordinates, &coords)); 404 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 405 PetscCall(VecDestroy(&coordinates)); 406 PetscFunctionReturn(PETSC_SUCCESS); 407 } 408 409 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[]) 410 { 411 const PetscInt numVertices = (edges[0] + 1) * (edges[1] + 1); 412 const PetscInt numEdges = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1]; 413 PetscInt markerTop = 1; 414 PetscInt markerBottom = 1; 415 PetscInt markerRight = 1; 416 PetscInt markerLeft = 1; 417 PetscBool markerSeparate = PETSC_FALSE; 418 Vec coordinates; 419 PetscSection coordSection; 420 PetscScalar *coords; 421 PetscInt coordSize; 422 PetscMPIInt rank; 423 PetscInt v, vx, vy; 424 425 PetscFunctionBegin; 426 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 427 if (markerSeparate) { 428 markerTop = 3; 429 markerBottom = 1; 430 markerRight = 2; 431 markerLeft = 4; 432 } 433 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 434 if (rank == 0) { 435 PetscInt e, ex, ey; 436 437 PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices)); 438 for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 439 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 440 for (vx = 0; vx <= edges[0]; vx++) { 441 for (ey = 0; ey < edges[1]; ey++) { 442 PetscInt edge = vx * edges[1] + ey + edges[0] * (edges[1] + 1); 443 PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges; 444 PetscInt cone[2]; 445 446 cone[0] = vertex; 447 cone[1] = vertex + edges[0] + 1; 448 PetscCall(DMPlexSetCone(dm, edge, cone)); 449 if (vx == edges[0]) { 450 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 451 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 452 if (ey == edges[1] - 1) { 453 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 454 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight)); 455 } 456 } else if (vx == 0) { 457 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 458 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 459 if (ey == edges[1] - 1) { 460 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 461 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft)); 462 } 463 } 464 } 465 } 466 for (vy = 0; vy <= edges[1]; vy++) { 467 for (ex = 0; ex < edges[0]; ex++) { 468 PetscInt edge = vy * edges[0] + ex; 469 PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges; 470 PetscInt cone[2]; 471 472 cone[0] = vertex; 473 cone[1] = vertex + 1; 474 PetscCall(DMPlexSetCone(dm, edge, cone)); 475 if (vy == edges[1]) { 476 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 477 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 478 if (ex == edges[0] - 1) { 479 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 480 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop)); 481 } 482 } else if (vy == 0) { 483 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 484 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 485 if (ex == edges[0] - 1) { 486 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 487 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom)); 488 } 489 } 490 } 491 } 492 } 493 PetscCall(DMPlexSymmetrize(dm)); 494 PetscCall(DMPlexStratify(dm)); 495 /* Build coordinates */ 496 PetscCall(DMSetCoordinateDim(dm, 2)); 497 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 498 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 499 PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices)); 500 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2)); 501 for (v = numEdges; v < numEdges + numVertices; ++v) { 502 PetscCall(PetscSectionSetDof(coordSection, v, 2)); 503 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2)); 504 } 505 PetscCall(PetscSectionSetUp(coordSection)); 506 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 507 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 508 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 509 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 510 PetscCall(VecSetBlockSize(coordinates, 2)); 511 PetscCall(VecSetType(coordinates, VECSTANDARD)); 512 PetscCall(VecGetArray(coordinates, &coords)); 513 for (vy = 0; vy <= edges[1]; ++vy) { 514 for (vx = 0; vx <= edges[0]; ++vx) { 515 coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx; 516 coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy; 517 } 518 } 519 PetscCall(VecRestoreArray(coordinates, &coords)); 520 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 521 PetscCall(VecDestroy(&coordinates)); 522 PetscFunctionReturn(PETSC_SUCCESS); 523 } 524 525 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[]) 526 { 527 PetscInt vertices[3], numVertices; 528 PetscInt numFaces = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2]; 529 PetscInt markerTop = 1; 530 PetscInt markerBottom = 1; 531 PetscInt markerFront = 1; 532 PetscInt markerBack = 1; 533 PetscInt markerRight = 1; 534 PetscInt markerLeft = 1; 535 PetscBool markerSeparate = PETSC_FALSE; 536 Vec coordinates; 537 PetscSection coordSection; 538 PetscScalar *coords; 539 PetscInt coordSize; 540 PetscMPIInt rank; 541 PetscInt v, vx, vy, vz; 542 PetscInt voffset, iface = 0, cone[4]; 543 544 PetscFunctionBegin; 545 PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side"); 546 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 547 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 548 if (markerSeparate) { 549 markerBottom = 1; 550 markerTop = 2; 551 markerFront = 3; 552 markerBack = 4; 553 markerRight = 5; 554 markerLeft = 6; 555 } 556 vertices[0] = faces[0] + 1; 557 vertices[1] = faces[1] + 1; 558 vertices[2] = faces[2] + 1; 559 numVertices = vertices[0] * vertices[1] * vertices[2]; 560 if (rank == 0) { 561 PetscInt f; 562 563 PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices)); 564 for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4)); 565 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 566 567 /* Side 0 (Top) */ 568 for (vy = 0; vy < faces[1]; vy++) { 569 for (vx = 0; vx < faces[0]; vx++) { 570 voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx; 571 cone[0] = voffset; 572 cone[1] = voffset + 1; 573 cone[2] = voffset + vertices[0] + 1; 574 cone[3] = voffset + vertices[0]; 575 PetscCall(DMPlexSetCone(dm, iface, cone)); 576 PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop)); 577 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop)); 578 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop)); 579 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop)); 580 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop)); 581 iface++; 582 } 583 } 584 585 /* Side 1 (Bottom) */ 586 for (vy = 0; vy < faces[1]; vy++) { 587 for (vx = 0; vx < faces[0]; vx++) { 588 voffset = numFaces + vy * (faces[0] + 1) + vx; 589 cone[0] = voffset + 1; 590 cone[1] = voffset; 591 cone[2] = voffset + vertices[0]; 592 cone[3] = voffset + vertices[0] + 1; 593 PetscCall(DMPlexSetCone(dm, iface, cone)); 594 PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom)); 595 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom)); 596 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom)); 597 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom)); 598 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom)); 599 iface++; 600 } 601 } 602 603 /* Side 2 (Front) */ 604 for (vz = 0; vz < faces[2]; vz++) { 605 for (vx = 0; vx < faces[0]; vx++) { 606 voffset = numFaces + vz * vertices[0] * vertices[1] + vx; 607 cone[0] = voffset; 608 cone[1] = voffset + 1; 609 cone[2] = voffset + vertices[0] * vertices[1] + 1; 610 cone[3] = voffset + vertices[0] * vertices[1]; 611 PetscCall(DMPlexSetCone(dm, iface, cone)); 612 PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront)); 613 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront)); 614 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront)); 615 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront)); 616 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront)); 617 iface++; 618 } 619 } 620 621 /* Side 3 (Back) */ 622 for (vz = 0; vz < faces[2]; vz++) { 623 for (vx = 0; vx < faces[0]; vx++) { 624 voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx; 625 cone[0] = voffset + vertices[0] * vertices[1]; 626 cone[1] = voffset + vertices[0] * vertices[1] + 1; 627 cone[2] = voffset + 1; 628 cone[3] = voffset; 629 PetscCall(DMPlexSetCone(dm, iface, cone)); 630 PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack)); 631 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack)); 632 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack)); 633 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack)); 634 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack)); 635 iface++; 636 } 637 } 638 639 /* Side 4 (Left) */ 640 for (vz = 0; vz < faces[2]; vz++) { 641 for (vy = 0; vy < faces[1]; vy++) { 642 voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0]; 643 cone[0] = voffset; 644 cone[1] = voffset + vertices[0] * vertices[1]; 645 cone[2] = voffset + vertices[0] * vertices[1] + vertices[0]; 646 cone[3] = voffset + vertices[0]; 647 PetscCall(DMPlexSetCone(dm, iface, cone)); 648 PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft)); 649 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft)); 650 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft)); 651 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft)); 652 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft)); 653 iface++; 654 } 655 } 656 657 /* Side 5 (Right) */ 658 for (vz = 0; vz < faces[2]; vz++) { 659 for (vy = 0; vy < faces[1]; vy++) { 660 voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0]; 661 cone[0] = voffset + vertices[0] * vertices[1]; 662 cone[1] = voffset; 663 cone[2] = voffset + vertices[0]; 664 cone[3] = voffset + vertices[0] * vertices[1] + vertices[0]; 665 PetscCall(DMPlexSetCone(dm, iface, cone)); 666 PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight)); 667 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight)); 668 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight)); 669 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight)); 670 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight)); 671 iface++; 672 } 673 } 674 } 675 PetscCall(DMPlexSymmetrize(dm)); 676 PetscCall(DMPlexStratify(dm)); 677 /* Build coordinates */ 678 PetscCall(DMSetCoordinateDim(dm, 3)); 679 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 680 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 681 PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices)); 682 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3)); 683 for (v = numFaces; v < numFaces + numVertices; ++v) { 684 PetscCall(PetscSectionSetDof(coordSection, v, 3)); 685 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3)); 686 } 687 PetscCall(PetscSectionSetUp(coordSection)); 688 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 689 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 690 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 691 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 692 PetscCall(VecSetBlockSize(coordinates, 3)); 693 PetscCall(VecSetType(coordinates, VECSTANDARD)); 694 PetscCall(VecGetArray(coordinates, &coords)); 695 for (vz = 0; vz <= faces[2]; ++vz) { 696 for (vy = 0; vy <= faces[1]; ++vy) { 697 for (vx = 0; vx <= faces[0]; ++vx) { 698 coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx; 699 coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy; 700 coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz; 701 } 702 } 703 } 704 PetscCall(VecRestoreArray(coordinates, &coords)); 705 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 706 PetscCall(VecDestroy(&coordinates)); 707 PetscFunctionReturn(PETSC_SUCCESS); 708 } 709 710 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate) 711 { 712 PetscFunctionBegin; 713 PetscValidLogicalCollectiveInt(dm, dim, 2); 714 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 715 PetscCall(DMSetDimension(dm, dim - 1)); 716 PetscCall(DMSetCoordinateDim(dm, dim)); 717 switch (dim) { 718 case 1: 719 PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces)); 720 break; 721 case 2: 722 PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces)); 723 break; 724 case 3: 725 PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces)); 726 break; 727 default: 728 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim); 729 } 730 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 731 if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 732 PetscFunctionReturn(PETSC_SUCCESS); 733 } 734 735 /*@C 736 DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra). 737 738 Collective 739 740 Input Parameters: 741 + comm - The communicator for the `DM` object 742 . dim - The spatial dimension of the box, so the resulting mesh is has dimension `dim`-1 743 . faces - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 744 . lower - The lower left corner, or `NULL` for (0, 0, 0) 745 . upper - The upper right corner, or `NULL` for (1, 1, 1) 746 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 747 748 Output Parameter: 749 . dm - The `DM` object 750 751 Level: beginner 752 753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()` 754 @*/ 755 PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm) 756 { 757 PetscInt fac[3] = {1, 1, 1}; 758 PetscReal low[3] = {0, 0, 0}; 759 PetscReal upp[3] = {1, 1, 1}; 760 761 PetscFunctionBegin; 762 PetscCall(DMCreate(comm, dm)); 763 PetscCall(DMSetType(*dm, DMPLEX)); 764 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate)); 765 PetscFunctionReturn(PETSC_SUCCESS); 766 } 767 768 static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd) 769 { 770 PetscInt i, fStart, fEnd, numCells = 0, numVerts = 0; 771 PetscInt numPoints[2], *coneSize, *cones, *coneOrientations; 772 PetscScalar *vertexCoords; 773 PetscReal L, maxCell; 774 PetscBool markerSeparate = PETSC_FALSE; 775 PetscInt markerLeft = 1, faceMarkerLeft = 1; 776 PetscInt markerRight = 1, faceMarkerRight = 2; 777 PetscBool wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE; 778 PetscMPIInt rank; 779 780 PetscFunctionBegin; 781 PetscAssertPointer(dm, 1); 782 783 PetscCall(DMSetDimension(dm, 1)); 784 PetscCall(DMCreateLabel(dm, "marker")); 785 PetscCall(DMCreateLabel(dm, "Face Sets")); 786 787 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 788 if (rank == 0) numCells = segments; 789 if (rank == 0) numVerts = segments + (wrap ? 0 : 1); 790 791 numPoints[0] = numVerts; 792 numPoints[1] = numCells; 793 PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords)); 794 PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts)); 795 for (i = 0; i < numCells; ++i) coneSize[i] = 2; 796 for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0; 797 for (i = 0; i < numCells; ++i) { 798 cones[2 * i] = numCells + i % numVerts; 799 cones[2 * i + 1] = numCells + (i + 1) % numVerts; 800 } 801 for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells); 802 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 803 PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords)); 804 805 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 806 if (markerSeparate) { 807 markerLeft = faceMarkerLeft; 808 markerRight = faceMarkerRight; 809 } 810 if (!wrap && rank == 0) { 811 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 812 PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft)); 813 PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight)); 814 PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft)); 815 PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight)); 816 } 817 if (wrap) { 818 L = upper - lower; 819 maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments)); 820 PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L)); 821 } 822 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 823 PetscFunctionReturn(PETSC_SUCCESS); 824 } 825 826 static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate) 827 { 828 DM boundary, vol; 829 DMLabel bdlabel; 830 831 PetscFunctionBegin; 832 PetscAssertPointer(dm, 1); 833 for (PetscInt i = 0; i < dim; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity is not supported for simplex meshes"); 834 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary)); 835 PetscCall(DMSetType(boundary, DMPLEX)); 836 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE)); 837 PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol)); 838 PetscCall(DMGetLabel(vol, "marker", &bdlabel)); 839 if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel)); 840 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol)); 841 PetscCall(DMPlexReplace_Internal(dm, &vol)); 842 PetscCall(DMDestroy(&boundary)); 843 PetscFunctionReturn(PETSC_SUCCESS); 844 } 845 846 static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ) 847 { 848 DMLabel cutLabel = NULL; 849 PetscInt markerTop = 1, faceMarkerTop = 1; 850 PetscInt markerBottom = 1, faceMarkerBottom = 1; 851 PetscInt markerFront = 1, faceMarkerFront = 1; 852 PetscInt markerBack = 1, faceMarkerBack = 1; 853 PetscInt markerRight = 1, faceMarkerRight = 1; 854 PetscInt markerLeft = 1, faceMarkerLeft = 1; 855 PetscInt dim; 856 PetscBool markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE; 857 PetscMPIInt rank; 858 859 PetscFunctionBegin; 860 PetscCall(DMGetDimension(dm, &dim)); 861 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 862 PetscCall(DMCreateLabel(dm, "marker")); 863 PetscCall(DMCreateLabel(dm, "Face Sets")); 864 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL)); 865 if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST || bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST || bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) { 866 if (cutMarker) { 867 PetscCall(DMCreateLabel(dm, "periodic_cut")); 868 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 869 } 870 } 871 switch (dim) { 872 case 2: 873 faceMarkerTop = 3; 874 faceMarkerBottom = 1; 875 faceMarkerRight = 2; 876 faceMarkerLeft = 4; 877 break; 878 case 3: 879 faceMarkerBottom = 1; 880 faceMarkerTop = 2; 881 faceMarkerFront = 3; 882 faceMarkerBack = 4; 883 faceMarkerRight = 5; 884 faceMarkerLeft = 6; 885 break; 886 default: 887 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim); 888 } 889 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 890 if (markerSeparate) { 891 markerBottom = faceMarkerBottom; 892 markerTop = faceMarkerTop; 893 markerFront = faceMarkerFront; 894 markerBack = faceMarkerBack; 895 markerRight = faceMarkerRight; 896 markerLeft = faceMarkerLeft; 897 } 898 { 899 const PetscInt numXEdges = rank == 0 ? edges[0] : 0; 900 const PetscInt numYEdges = rank == 0 ? edges[1] : 0; 901 const PetscInt numZEdges = rank == 0 ? edges[2] : 0; 902 const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0; 903 const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0; 904 const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0; 905 const PetscInt numCells = numXEdges * numYEdges * numZEdges; 906 const PetscInt numXFaces = numYEdges * numZEdges; 907 const PetscInt numYFaces = numXEdges * numZEdges; 908 const PetscInt numZFaces = numXEdges * numYEdges; 909 const PetscInt numTotXFaces = numXVertices * numXFaces; 910 const PetscInt numTotYFaces = numYVertices * numYFaces; 911 const PetscInt numTotZFaces = numZVertices * numZFaces; 912 const PetscInt numFaces = numTotXFaces + numTotYFaces + numTotZFaces; 913 const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices; 914 const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices; 915 const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices; 916 const PetscInt numVertices = numXVertices * numYVertices * numZVertices; 917 const PetscInt numEdges = numTotXEdges + numTotYEdges + numTotZEdges; 918 const PetscInt firstVertex = (dim == 2) ? numFaces : numCells; 919 const PetscInt firstXFace = (dim == 2) ? 0 : numCells + numVertices; 920 const PetscInt firstYFace = firstXFace + numTotXFaces; 921 const PetscInt firstZFace = firstYFace + numTotYFaces; 922 const PetscInt firstXEdge = numCells + numFaces + numVertices; 923 const PetscInt firstYEdge = firstXEdge + numTotXEdges; 924 const PetscInt firstZEdge = firstYEdge + numTotYEdges; 925 Vec coordinates; 926 PetscSection coordSection; 927 PetscScalar *coords; 928 PetscInt coordSize; 929 PetscInt v, vx, vy, vz; 930 PetscInt c, f, fx, fy, fz, e, ex, ey, ez; 931 932 PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices)); 933 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6)); 934 for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4)); 935 for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 936 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 937 /* Build cells */ 938 for (fz = 0; fz < numZEdges; ++fz) { 939 for (fy = 0; fy < numYEdges; ++fy) { 940 for (fx = 0; fx < numXEdges; ++fx) { 941 PetscInt cell = (fz * numYEdges + fy) * numXEdges + fx; 942 PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz; 943 PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices); 944 PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy; 945 PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices); 946 PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx; 947 PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices); 948 /* B, T, F, K, R, L */ 949 PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */ 950 PetscInt cone[6]; 951 952 /* no boundary twisting in 3D */ 953 cone[0] = faceB; 954 cone[1] = faceT; 955 cone[2] = faceF; 956 cone[3] = faceK; 957 cone[4] = faceR; 958 cone[5] = faceL; 959 PetscCall(DMPlexSetCone(dm, cell, cone)); 960 PetscCall(DMPlexSetConeOrientation(dm, cell, ornt)); 961 if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2)); 962 if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2)); 963 if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2)); 964 } 965 } 966 } 967 /* Build x faces */ 968 for (fz = 0; fz < numZEdges; ++fz) { 969 for (fy = 0; fy < numYEdges; ++fy) { 970 for (fx = 0; fx < numXVertices; ++fx) { 971 PetscInt face = firstXFace + (fz * numYEdges + fy) * numXVertices + fx; 972 PetscInt edgeL = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz; 973 PetscInt edgeR = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz; 974 PetscInt edgeB = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy; 975 PetscInt edgeT = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy; 976 PetscInt ornt[4] = {0, 0, -1, -1}; 977 PetscInt cone[4]; 978 979 if (dim == 3) { 980 /* markers */ 981 if (bdX != DM_BOUNDARY_PERIODIC) { 982 if (fx == numXVertices - 1) { 983 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight)); 984 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight)); 985 } else if (fx == 0) { 986 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft)); 987 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft)); 988 } 989 } 990 } 991 cone[0] = edgeB; 992 cone[1] = edgeR; 993 cone[2] = edgeT; 994 cone[3] = edgeL; 995 PetscCall(DMPlexSetCone(dm, face, cone)); 996 PetscCall(DMPlexSetConeOrientation(dm, face, ornt)); 997 } 998 } 999 } 1000 /* Build y faces */ 1001 for (fz = 0; fz < numZEdges; ++fz) { 1002 for (fx = 0; fx < numXEdges; ++fx) { 1003 for (fy = 0; fy < numYVertices; ++fy) { 1004 PetscInt face = firstYFace + (fz * numXEdges + fx) * numYVertices + fy; 1005 PetscInt edgeL = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz; 1006 PetscInt edgeR = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz; 1007 PetscInt edgeB = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx; 1008 PetscInt edgeT = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx; 1009 PetscInt ornt[4] = {0, 0, -1, -1}; 1010 PetscInt cone[4]; 1011 1012 if (dim == 3) { 1013 /* markers */ 1014 if (bdY != DM_BOUNDARY_PERIODIC) { 1015 if (fy == numYVertices - 1) { 1016 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack)); 1017 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack)); 1018 } else if (fy == 0) { 1019 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront)); 1020 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront)); 1021 } 1022 } 1023 } 1024 cone[0] = edgeB; 1025 cone[1] = edgeR; 1026 cone[2] = edgeT; 1027 cone[3] = edgeL; 1028 PetscCall(DMPlexSetCone(dm, face, cone)); 1029 PetscCall(DMPlexSetConeOrientation(dm, face, ornt)); 1030 } 1031 } 1032 } 1033 /* Build z faces */ 1034 for (fy = 0; fy < numYEdges; ++fy) { 1035 for (fx = 0; fx < numXEdges; ++fx) { 1036 for (fz = 0; fz < numZVertices; fz++) { 1037 PetscInt face = firstZFace + (fy * numXEdges + fx) * numZVertices + fz; 1038 PetscInt edgeL = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy; 1039 PetscInt edgeR = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy; 1040 PetscInt edgeB = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx; 1041 PetscInt edgeT = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx; 1042 PetscInt ornt[4] = {0, 0, -1, -1}; 1043 PetscInt cone[4]; 1044 1045 if (dim == 2) { 1046 if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) { 1047 edgeR += numYEdges - 1 - 2 * fy; 1048 ornt[1] = -1; 1049 } 1050 if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) { 1051 edgeT += numXEdges - 1 - 2 * fx; 1052 ornt[2] = 0; 1053 } 1054 if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2)); 1055 if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2)); 1056 } else { 1057 /* markers */ 1058 if (bdZ != DM_BOUNDARY_PERIODIC) { 1059 if (fz == numZVertices - 1) { 1060 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop)); 1061 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop)); 1062 } else if (fz == 0) { 1063 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom)); 1064 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom)); 1065 } 1066 } 1067 } 1068 cone[0] = edgeB; 1069 cone[1] = edgeR; 1070 cone[2] = edgeT; 1071 cone[3] = edgeL; 1072 PetscCall(DMPlexSetCone(dm, face, cone)); 1073 PetscCall(DMPlexSetConeOrientation(dm, face, ornt)); 1074 } 1075 } 1076 } 1077 /* Build Z edges*/ 1078 for (vy = 0; vy < numYVertices; vy++) { 1079 for (vx = 0; vx < numXVertices; vx++) { 1080 for (ez = 0; ez < numZEdges; ez++) { 1081 const PetscInt edge = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez; 1082 const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx; 1083 const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx; 1084 PetscInt cone[2]; 1085 1086 cone[0] = vertexB; 1087 cone[1] = vertexT; 1088 PetscCall(DMPlexSetCone(dm, edge, cone)); 1089 if (dim == 3) { 1090 if (bdX != DM_BOUNDARY_PERIODIC) { 1091 if (vx == numXVertices - 1) { 1092 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1093 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1094 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1095 } else if (vx == 0) { 1096 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1097 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1098 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1099 } 1100 } 1101 if (bdY != DM_BOUNDARY_PERIODIC) { 1102 if (vy == numYVertices - 1) { 1103 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack)); 1104 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack)); 1105 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack)); 1106 } else if (vy == 0) { 1107 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront)); 1108 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront)); 1109 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront)); 1110 } 1111 } 1112 } 1113 } 1114 } 1115 } 1116 /* Build Y edges*/ 1117 for (vz = 0; vz < numZVertices; vz++) { 1118 for (vx = 0; vx < numXVertices; vx++) { 1119 for (ey = 0; ey < numYEdges; ey++) { 1120 const PetscInt nextv = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx; 1121 const PetscInt edge = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey; 1122 const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx; 1123 const PetscInt vertexK = firstVertex + nextv; 1124 PetscInt cone[2]; 1125 1126 cone[0] = vertexF; 1127 cone[1] = vertexK; 1128 PetscCall(DMPlexSetCone(dm, edge, cone)); 1129 if (dim == 2) { 1130 if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) { 1131 if (vx == numXVertices - 1) { 1132 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight)); 1133 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1134 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1135 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1136 } else if (vx == 0) { 1137 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft)); 1138 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1139 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1140 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1141 } 1142 } else { 1143 if (vx == 0 && cutLabel) { 1144 PetscCall(DMLabelSetValue(cutLabel, edge, 1)); 1145 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1)); 1146 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1)); 1147 } 1148 } 1149 } else { 1150 if (bdX != DM_BOUNDARY_PERIODIC) { 1151 if (vx == numXVertices - 1) { 1152 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1153 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1154 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1155 } else if (vx == 0) { 1156 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1157 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1158 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1159 } 1160 } 1161 if (bdZ != DM_BOUNDARY_PERIODIC) { 1162 if (vz == numZVertices - 1) { 1163 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1164 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1165 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1166 } else if (vz == 0) { 1167 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1168 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1169 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1170 } 1171 } 1172 } 1173 } 1174 } 1175 } 1176 /* Build X edges*/ 1177 for (vz = 0; vz < numZVertices; vz++) { 1178 for (vy = 0; vy < numYVertices; vy++) { 1179 for (ex = 0; ex < numXEdges; ex++) { 1180 const PetscInt nextv = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices; 1181 const PetscInt edge = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex; 1182 const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex; 1183 const PetscInt vertexR = firstVertex + nextv; 1184 PetscInt cone[2]; 1185 1186 cone[0] = vertexL; 1187 cone[1] = vertexR; 1188 PetscCall(DMPlexSetCone(dm, edge, cone)); 1189 if (dim == 2) { 1190 if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) { 1191 if (vy == numYVertices - 1) { 1192 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop)); 1193 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1194 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1195 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1196 } else if (vy == 0) { 1197 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom)); 1198 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1199 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1200 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1201 } 1202 } else { 1203 if (vy == 0 && cutLabel) { 1204 PetscCall(DMLabelSetValue(cutLabel, edge, 1)); 1205 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1)); 1206 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1)); 1207 } 1208 } 1209 } else { 1210 if (bdY != DM_BOUNDARY_PERIODIC) { 1211 if (vy == numYVertices - 1) { 1212 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack)); 1213 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack)); 1214 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack)); 1215 } else if (vy == 0) { 1216 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront)); 1217 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront)); 1218 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront)); 1219 } 1220 } 1221 if (bdZ != DM_BOUNDARY_PERIODIC) { 1222 if (vz == numZVertices - 1) { 1223 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1224 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1225 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1226 } else if (vz == 0) { 1227 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1228 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1229 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1230 } 1231 } 1232 } 1233 } 1234 } 1235 } 1236 PetscCall(DMPlexSymmetrize(dm)); 1237 PetscCall(DMPlexStratify(dm)); 1238 /* Build coordinates */ 1239 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1240 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1241 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 1242 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices)); 1243 for (v = firstVertex; v < firstVertex + numVertices; ++v) { 1244 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 1245 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 1246 } 1247 PetscCall(PetscSectionSetUp(coordSection)); 1248 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 1249 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 1250 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 1251 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 1252 PetscCall(VecSetBlockSize(coordinates, dim)); 1253 PetscCall(VecSetType(coordinates, VECSTANDARD)); 1254 PetscCall(VecGetArray(coordinates, &coords)); 1255 for (vz = 0; vz < numZVertices; ++vz) { 1256 for (vy = 0; vy < numYVertices; ++vy) { 1257 for (vx = 0; vx < numXVertices; ++vx) { 1258 coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx; 1259 coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy; 1260 if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz; 1261 } 1262 } 1263 } 1264 PetscCall(VecRestoreArray(coordinates, &coords)); 1265 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1266 PetscCall(VecDestroy(&coordinates)); 1267 } 1268 PetscFunctionReturn(PETSC_SUCCESS); 1269 } 1270 1271 static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[]) 1272 { 1273 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 1274 PetscInt fac[3] = {0, 0, 0}, d; 1275 1276 PetscFunctionBegin; 1277 PetscAssertPointer(dm, 1); 1278 PetscValidLogicalCollectiveInt(dm, dim, 2); 1279 PetscCall(DMSetDimension(dm, dim)); 1280 for (d = 0; d < dim; ++d) { 1281 fac[d] = faces[d]; 1282 bdt[d] = periodicity[d]; 1283 } 1284 PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2])); 1285 if (periodicity[0] == DM_BOUNDARY_PERIODIC || periodicity[0] == DM_BOUNDARY_TWIST || periodicity[1] == DM_BOUNDARY_PERIODIC || periodicity[1] == DM_BOUNDARY_TWIST || (dim > 2 && (periodicity[2] == DM_BOUNDARY_PERIODIC || periodicity[2] == DM_BOUNDARY_TWIST))) { 1286 PetscReal L[3] = {-1., -1., 0.}; 1287 PetscReal maxCell[3] = {-1., -1., 0.}; 1288 1289 for (d = 0; d < dim; ++d) { 1290 if (periodicity[d] != DM_BOUNDARY_NONE) { 1291 L[d] = upper[d] - lower[d]; 1292 maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d])); 1293 } 1294 } 1295 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 1296 } 1297 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 1298 PetscFunctionReturn(PETSC_SUCCESS); 1299 } 1300 1301 static PetscErrorCode DMPlexCreateBoxMesh_Internal(DM dm, DMPlexShape shape, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate) 1302 { 1303 PetscFunctionBegin; 1304 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 1305 if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate)); 1306 else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0])); 1307 else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate)); 1308 else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity)); 1309 if (!interpolate && dim > 1 && !simplex) { 1310 DM udm; 1311 1312 PetscCall(DMPlexUninterpolate(dm, &udm)); 1313 PetscCall(DMPlexCopyCoordinates(dm, udm)); 1314 PetscCall(DMPlexReplace_Internal(dm, &udm)); 1315 } 1316 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 1317 PetscFunctionReturn(PETSC_SUCCESS); 1318 } 1319 1320 /*@C 1321 DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra). 1322 1323 Collective 1324 1325 Input Parameters: 1326 + comm - The communicator for the `DM` object 1327 . dim - The spatial dimension 1328 . simplex - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells 1329 . faces - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 1330 . lower - The lower left corner, or `NULL` for (0, 0, 0) 1331 . upper - The upper right corner, or `NULL` for (1, 1, 1) 1332 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE` 1333 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 1334 1335 Output Parameter: 1336 . dm - The `DM` object 1337 1338 Level: beginner 1339 1340 Note: 1341 To customize this mesh using options, use 1342 .vb 1343 DMCreate(comm, &dm); 1344 DMSetType(dm, DMPLEX); 1345 DMSetFromOptions(dm); 1346 .ve 1347 and use the options in `DMSetFromOptions()`. 1348 1349 Here is the numbering returned for 2 faces in each direction for tensor cells\: 1350 .vb 1351 10---17---11---18----12 1352 | | | 1353 | | | 1354 20 2 22 3 24 1355 | | | 1356 | | | 1357 7---15----8---16----9 1358 | | | 1359 | | | 1360 19 0 21 1 23 1361 | | | 1362 | | | 1363 4---13----5---14----6 1364 .ve 1365 and for simplicial cells 1366 .vb 1367 14----8---15----9----16 1368 |\ 5 |\ 7 | 1369 | \ | \ | 1370 13 2 14 3 15 1371 | 4 \ | 6 \ | 1372 | \ | \ | 1373 11----6---12----7----13 1374 |\ |\ | 1375 | \ 1 | \ 3 | 1376 10 0 11 1 12 1377 | 0 \ | 2 \ | 1378 | \ | \ | 1379 8----4----9----5----10 1380 .ve 1381 1382 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()` 1383 @*/ 1384 PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, DM *dm) 1385 { 1386 PetscInt fac[3] = {1, 1, 1}; 1387 PetscReal low[3] = {0, 0, 0}; 1388 PetscReal upp[3] = {1, 1, 1}; 1389 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 1390 1391 PetscFunctionBegin; 1392 PetscCall(DMCreate(comm, dm)); 1393 PetscCall(DMSetType(*dm, DMPLEX)); 1394 PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate)); 1395 if (periodicity) PetscCall(DMLocalizeCoordinates(*dm)); 1396 PetscFunctionReturn(PETSC_SUCCESS); 1397 } 1398 1399 static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[]) 1400 { 1401 DM bdm, vol; 1402 PetscInt i; 1403 1404 PetscFunctionBegin; 1405 // TODO Now we can support periodicity 1406 for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported"); 1407 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm)); 1408 PetscCall(DMSetType(bdm, DMPLEX)); 1409 PetscCall(DMSetDimension(bdm, 2)); 1410 PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0)); 1411 PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE)); 1412 PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, &vol)); 1413 PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0)); 1414 PetscCall(DMDestroy(&bdm)); 1415 PetscCall(DMPlexReplace_Internal(dm, &vol)); 1416 if (lower[2] != 0.0) { 1417 Vec v; 1418 PetscScalar *x; 1419 PetscInt cDim, n; 1420 1421 PetscCall(DMGetCoordinatesLocal(dm, &v)); 1422 PetscCall(VecGetBlockSize(v, &cDim)); 1423 PetscCall(VecGetLocalSize(v, &n)); 1424 PetscCall(VecGetArray(v, &x)); 1425 x += cDim; 1426 for (i = 0; i < n; i += cDim) x[i] += lower[2]; 1427 PetscCall(VecRestoreArray(v, &x)); 1428 PetscCall(DMSetCoordinatesLocal(dm, v)); 1429 } 1430 PetscFunctionReturn(PETSC_SUCCESS); 1431 } 1432 1433 /*@ 1434 DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tesselating the (x,y) plane and extruding in the third direction using wedge cells. 1435 1436 Collective 1437 1438 Input Parameters: 1439 + comm - The communicator for the `DM` object 1440 . faces - Number of faces per dimension, or `NULL` for (1, 1, 1) 1441 . lower - The lower left corner, or `NULL` for (0, 0, 0) 1442 . upper - The upper right corner, or `NULL` for (1, 1, 1) 1443 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE` 1444 . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first 1445 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 1446 1447 Output Parameter: 1448 . dm - The `DM` object 1449 1450 Level: beginner 1451 1452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 1453 @*/ 1454 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm) 1455 { 1456 PetscInt fac[3] = {1, 1, 1}; 1457 PetscReal low[3] = {0, 0, 0}; 1458 PetscReal upp[3] = {1, 1, 1}; 1459 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 1460 1461 PetscFunctionBegin; 1462 PetscCall(DMCreate(comm, dm)); 1463 PetscCall(DMSetType(*dm, DMPLEX)); 1464 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt)); 1465 if (!interpolate) { 1466 DM udm; 1467 1468 PetscCall(DMPlexUninterpolate(*dm, &udm)); 1469 PetscCall(DMPlexReplace_Internal(*dm, &udm)); 1470 } 1471 if (periodicity) PetscCall(DMLocalizeCoordinates(*dm)); 1472 PetscFunctionReturn(PETSC_SUCCESS); 1473 } 1474 1475 /* 1476 DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension. 1477 1478 Input Parameters: 1479 + len - The length of the tuple 1480 . max - The maximum for each dimension, so values are in [0, max) 1481 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition 1482 1483 Output Parameter: 1484 . tup - A tuple of `len` integers whose entries are at most `max` 1485 1486 Level: developer 1487 1488 Note: 1489 Ordering is lexicographic with lowest index as least significant in ordering. 1490 e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}. 1491 1492 .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal() 1493 */ 1494 static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[]) 1495 { 1496 PetscInt i; 1497 1498 PetscFunctionBegin; 1499 for (i = 0; i < len; ++i) { 1500 if (tup[i] < max[i] - 1) { 1501 break; 1502 } else { 1503 tup[i] = 0; 1504 } 1505 } 1506 if (i == len) tup[i - 1] = max[i - 1]; 1507 else ++tup[i]; 1508 PetscFunctionReturn(PETSC_SUCCESS); 1509 } 1510 1511 static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[]) 1512 { 1513 PetscInt i, idx = tup[len - 1]; 1514 1515 for (i = len - 2; i >= 0; --i) { 1516 idx *= max[i]; 1517 idx += tup[i]; 1518 } 1519 return idx; 1520 } 1521 1522 static PetscErrorCode DestroyExtent_Private(void *extent) 1523 { 1524 return PetscFree(extent); 1525 } 1526 1527 static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], const DMBoundaryType bd[]) 1528 { 1529 Vec coordinates; 1530 PetscSection coordSection; 1531 DMLabel cutLabel = NULL; 1532 PetscBool cutMarker = PETSC_FALSE; 1533 PetscBool periodic = PETSC_FALSE; 1534 PetscInt numCells = 1, c; 1535 PetscInt numVertices = 1, v; 1536 PetscScalar *coords; 1537 PetscInt *vertices, *vert, *vtmp, *supp, cone[2]; 1538 PetscInt d, e, cell = 0, coordSize; 1539 PetscMPIInt rank; 1540 1541 PetscFunctionBegin; 1542 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1543 PetscCall(DMSetDimension(dm, dim)); 1544 PetscCall(PetscCalloc4(dim, &vertices, dim, &vert, dim, &vtmp, 2 * dim, &supp)); 1545 PetscCall(DMCreateLabel(dm, "marker")); 1546 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL)); 1547 for (d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE; 1548 if (periodic && cutMarker) { 1549 PetscCall(DMCreateLabel(dm, "periodic_cut")); 1550 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 1551 } 1552 for (d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Hypercubic mesh must be periodic now"); 1553 for (d = 0; d < dim; ++d) { 1554 vertices[d] = edges[d]; 1555 numVertices *= vertices[d]; 1556 } 1557 numCells = numVertices * dim; 1558 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 1559 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2)); 1560 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim)); 1561 /* TODO Loop over boundary and reset support sizes */ 1562 PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */ 1563 /* Build cell cones and vertex supports */ 1564 PetscCall(DMCreateLabel(dm, "celltype")); 1565 while (vert[dim - 1] < vertices[dim - 1]) { 1566 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells; 1567 PetscInt s = 0; 1568 1569 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex)); 1570 for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d])); 1571 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1572 PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT)); 1573 for (d = 0; d < dim; ++d) { 1574 for (e = 0; e < dim; ++e) vtmp[e] = vert[e]; 1575 vtmp[d] = (vert[d] + 1) % vertices[d]; 1576 cone[0] = vertex; 1577 cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells; 1578 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Vertex %" PetscInt_FMT ":", cone[1])); 1579 for (e = 0; e < dim; ++e) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vtmp[e])); 1580 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1581 PetscCall(DMPlexSetCone(dm, cell, cone)); 1582 PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT)); 1583 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1])); 1584 ++cell; 1585 } 1586 for (d = 0; d < dim; ++d) { 1587 for (e = 0; e < dim; ++e) vtmp[e] = vert[e]; 1588 vtmp[d] = (vert[d] + vertices[d] - 1) % vertices[d]; 1589 supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d; 1590 supp[s++] = (vertex - numCells) * dim + d; 1591 PetscCall(DMPlexSetSupport(dm, vertex, supp)); 1592 } 1593 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 1594 } 1595 PetscCall(DMPlexStratify(dm)); 1596 /* Build coordinates */ 1597 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1598 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1599 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 1600 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 1601 for (v = numCells; v < numCells + numVertices; ++v) { 1602 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 1603 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 1604 } 1605 PetscCall(PetscSectionSetUp(coordSection)); 1606 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 1607 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 1608 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 1609 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 1610 PetscCall(VecSetBlockSize(coordinates, dim)); 1611 PetscCall(VecSetType(coordinates, VECSTANDARD)); 1612 PetscCall(VecGetArray(coordinates, &coords)); 1613 for (d = 0; d < dim; ++d) vert[d] = 0; 1614 while (vert[dim - 1] < vertices[dim - 1]) { 1615 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert); 1616 1617 for (d = 0; d < dim; ++d) coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / vertices[d]) * vert[d]; 1618 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex)); 1619 for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d])); 1620 for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(coords[vertex * dim + d]))); 1621 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1622 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 1623 } 1624 PetscCall(VecRestoreArray(coordinates, &coords)); 1625 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1626 PetscCall(VecDestroy(&coordinates)); 1627 PetscCall(PetscFree4(vertices, vert, vtmp, supp)); 1628 //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper)); 1629 // Attach the extent 1630 { 1631 PetscContainer c; 1632 PetscInt *extent; 1633 1634 PetscCall(PetscMalloc1(dim, &extent)); 1635 for (PetscInt d = 0; d < dim; ++d) extent[d] = edges[d]; 1636 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c)); 1637 PetscCall(PetscContainerSetUserDestroy(c, DestroyExtent_Private)); 1638 PetscCall(PetscContainerSetPointer(c, extent)); 1639 PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c)); 1640 PetscCall(PetscContainerDestroy(&c)); 1641 } 1642 PetscFunctionReturn(PETSC_SUCCESS); 1643 } 1644 1645 /*@C 1646 DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges. 1647 1648 Collective 1649 1650 Input Parameters: 1651 + comm - The communicator for the DM object 1652 . dim - The spatial dimension 1653 . edges - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 1654 . lower - The lower left corner, or `NULL` for (0, 0, 0) 1655 - upper - The upper right corner, or `NULL` for (1, 1, 1) 1656 1657 Output Parameter: 1658 . dm - The DM object 1659 1660 Level: beginner 1661 1662 Note: 1663 If you want to customize this mesh using options, you just need to 1664 .vb 1665 DMCreate(comm, &dm); 1666 DMSetType(dm, DMPLEX); 1667 DMSetFromOptions(dm); 1668 .ve 1669 and use the options on the `DMSetFromOptions()` page. 1670 1671 The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively, 1672 .vb 1673 18--0-19--2-20--4-18 1674 | | | | 1675 13 15 17 13 1676 | | | | 1677 24-12-25-14-26-16-24 1678 | | | | 1679 7 9 11 7 1680 | | | | 1681 21--6-22--8-23-10-21 1682 | | | | 1683 1 3 5 1 1684 | | | | 1685 18--0-19--2-20--4-18 1686 .ve 1687 1688 .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()` 1689 @*/ 1690 PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], DM *dm) 1691 { 1692 PetscInt *edg; 1693 PetscReal *low, *upp; 1694 DMBoundaryType *bdt; 1695 PetscInt d; 1696 1697 PetscFunctionBegin; 1698 PetscCall(DMCreate(comm, dm)); 1699 PetscCall(DMSetType(*dm, DMPLEX)); 1700 PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt)); 1701 for (d = 0; d < dim; ++d) { 1702 edg[d] = edges ? edges[d] : 1; 1703 low[d] = lower ? lower[d] : 0.; 1704 upp[d] = upper ? upper[d] : 1.; 1705 bdt[d] = DM_BOUNDARY_PERIODIC; 1706 } 1707 PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, bdt)); 1708 PetscCall(PetscFree4(edg, low, upp, bdt)); 1709 PetscFunctionReturn(PETSC_SUCCESS); 1710 } 1711 1712 /*@C 1713 DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database. 1714 1715 Logically Collective 1716 1717 Input Parameters: 1718 + dm - the `DM` context 1719 - prefix - the prefix to prepend to all option names 1720 1721 Level: advanced 1722 1723 Note: 1724 A hyphen (-) must NOT be given at the beginning of the prefix name. 1725 The first character of all runtime options is AUTOMATICALLY the hyphen. 1726 1727 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()` 1728 @*/ 1729 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[]) 1730 { 1731 DM_Plex *mesh = (DM_Plex *)dm->data; 1732 1733 PetscFunctionBegin; 1734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1735 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix)); 1736 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix)); 1737 PetscFunctionReturn(PETSC_SUCCESS); 1738 } 1739 1740 /* Remap geometry to cylinder 1741 TODO: This only works for a single refinement, then it is broken 1742 1743 Interior square: Linear interpolation is correct 1744 The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing 1745 such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance 1746 1747 phi = arctan(y/x) 1748 d_close = sqrt(1/8 + 1/4 sin^2(phi)) 1749 d_far = sqrt(1/2 + sin^2(phi)) 1750 1751 so we remap them using 1752 1753 x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close) 1754 y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close) 1755 1756 If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y. 1757 */ 1758 static void snapToCylinder(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 1759 { 1760 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 1761 const PetscReal ds2 = 0.5 * dis; 1762 1763 if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) { 1764 f0[0] = u[0]; 1765 f0[1] = u[1]; 1766 } else { 1767 PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc; 1768 1769 x = PetscRealPart(u[0]); 1770 y = PetscRealPart(u[1]); 1771 phi = PetscAtan2Real(y, x); 1772 sinp = PetscSinReal(phi); 1773 cosp = PetscCosReal(phi); 1774 if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) { 1775 dc = PetscAbsReal(ds2 / sinp); 1776 df = PetscAbsReal(dis / sinp); 1777 xc = ds2 * x / PetscAbsReal(y); 1778 yc = ds2 * PetscSignReal(y); 1779 } else { 1780 dc = PetscAbsReal(ds2 / cosp); 1781 df = PetscAbsReal(dis / cosp); 1782 xc = ds2 * PetscSignReal(x); 1783 yc = ds2 * y / PetscAbsReal(x); 1784 } 1785 f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc); 1786 f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc); 1787 } 1788 f0[2] = u[2]; 1789 } 1790 1791 static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ) 1792 { 1793 const PetscInt dim = 3; 1794 PetscInt numCells, numVertices; 1795 PetscMPIInt rank; 1796 1797 PetscFunctionBegin; 1798 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 1799 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1800 PetscCall(DMSetDimension(dm, dim)); 1801 /* Create topology */ 1802 { 1803 PetscInt cone[8], c; 1804 1805 numCells = rank == 0 ? 5 : 0; 1806 numVertices = rank == 0 ? 16 : 0; 1807 if (periodicZ == DM_BOUNDARY_PERIODIC) { 1808 numCells *= 3; 1809 numVertices = rank == 0 ? 24 : 0; 1810 } 1811 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 1812 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8)); 1813 PetscCall(DMSetUp(dm)); 1814 if (rank == 0) { 1815 if (periodicZ == DM_BOUNDARY_PERIODIC) { 1816 cone[0] = 15; 1817 cone[1] = 18; 1818 cone[2] = 17; 1819 cone[3] = 16; 1820 cone[4] = 31; 1821 cone[5] = 32; 1822 cone[6] = 33; 1823 cone[7] = 34; 1824 PetscCall(DMPlexSetCone(dm, 0, cone)); 1825 cone[0] = 16; 1826 cone[1] = 17; 1827 cone[2] = 24; 1828 cone[3] = 23; 1829 cone[4] = 32; 1830 cone[5] = 36; 1831 cone[6] = 37; 1832 cone[7] = 33; /* 22 25 26 21 */ 1833 PetscCall(DMPlexSetCone(dm, 1, cone)); 1834 cone[0] = 18; 1835 cone[1] = 27; 1836 cone[2] = 24; 1837 cone[3] = 17; 1838 cone[4] = 34; 1839 cone[5] = 33; 1840 cone[6] = 37; 1841 cone[7] = 38; 1842 PetscCall(DMPlexSetCone(dm, 2, cone)); 1843 cone[0] = 29; 1844 cone[1] = 27; 1845 cone[2] = 18; 1846 cone[3] = 15; 1847 cone[4] = 35; 1848 cone[5] = 31; 1849 cone[6] = 34; 1850 cone[7] = 38; 1851 PetscCall(DMPlexSetCone(dm, 3, cone)); 1852 cone[0] = 29; 1853 cone[1] = 15; 1854 cone[2] = 16; 1855 cone[3] = 23; 1856 cone[4] = 35; 1857 cone[5] = 36; 1858 cone[6] = 32; 1859 cone[7] = 31; 1860 PetscCall(DMPlexSetCone(dm, 4, cone)); 1861 1862 cone[0] = 31; 1863 cone[1] = 34; 1864 cone[2] = 33; 1865 cone[3] = 32; 1866 cone[4] = 19; 1867 cone[5] = 22; 1868 cone[6] = 21; 1869 cone[7] = 20; 1870 PetscCall(DMPlexSetCone(dm, 5, cone)); 1871 cone[0] = 32; 1872 cone[1] = 33; 1873 cone[2] = 37; 1874 cone[3] = 36; 1875 cone[4] = 22; 1876 cone[5] = 25; 1877 cone[6] = 26; 1878 cone[7] = 21; 1879 PetscCall(DMPlexSetCone(dm, 6, cone)); 1880 cone[0] = 34; 1881 cone[1] = 38; 1882 cone[2] = 37; 1883 cone[3] = 33; 1884 cone[4] = 20; 1885 cone[5] = 21; 1886 cone[6] = 26; 1887 cone[7] = 28; 1888 PetscCall(DMPlexSetCone(dm, 7, cone)); 1889 cone[0] = 35; 1890 cone[1] = 38; 1891 cone[2] = 34; 1892 cone[3] = 31; 1893 cone[4] = 30; 1894 cone[5] = 19; 1895 cone[6] = 20; 1896 cone[7] = 28; 1897 PetscCall(DMPlexSetCone(dm, 8, cone)); 1898 cone[0] = 35; 1899 cone[1] = 31; 1900 cone[2] = 32; 1901 cone[3] = 36; 1902 cone[4] = 30; 1903 cone[5] = 25; 1904 cone[6] = 22; 1905 cone[7] = 19; 1906 PetscCall(DMPlexSetCone(dm, 9, cone)); 1907 1908 cone[0] = 19; 1909 cone[1] = 20; 1910 cone[2] = 21; 1911 cone[3] = 22; 1912 cone[4] = 15; 1913 cone[5] = 16; 1914 cone[6] = 17; 1915 cone[7] = 18; 1916 PetscCall(DMPlexSetCone(dm, 10, cone)); 1917 cone[0] = 22; 1918 cone[1] = 21; 1919 cone[2] = 26; 1920 cone[3] = 25; 1921 cone[4] = 16; 1922 cone[5] = 23; 1923 cone[6] = 24; 1924 cone[7] = 17; 1925 PetscCall(DMPlexSetCone(dm, 11, cone)); 1926 cone[0] = 20; 1927 cone[1] = 28; 1928 cone[2] = 26; 1929 cone[3] = 21; 1930 cone[4] = 18; 1931 cone[5] = 17; 1932 cone[6] = 24; 1933 cone[7] = 27; 1934 PetscCall(DMPlexSetCone(dm, 12, cone)); 1935 cone[0] = 30; 1936 cone[1] = 28; 1937 cone[2] = 20; 1938 cone[3] = 19; 1939 cone[4] = 29; 1940 cone[5] = 15; 1941 cone[6] = 18; 1942 cone[7] = 27; 1943 PetscCall(DMPlexSetCone(dm, 13, cone)); 1944 cone[0] = 30; 1945 cone[1] = 19; 1946 cone[2] = 22; 1947 cone[3] = 25; 1948 cone[4] = 29; 1949 cone[5] = 23; 1950 cone[6] = 16; 1951 cone[7] = 15; 1952 PetscCall(DMPlexSetCone(dm, 14, cone)); 1953 } else { 1954 cone[0] = 5; 1955 cone[1] = 8; 1956 cone[2] = 7; 1957 cone[3] = 6; 1958 cone[4] = 9; 1959 cone[5] = 12; 1960 cone[6] = 11; 1961 cone[7] = 10; 1962 PetscCall(DMPlexSetCone(dm, 0, cone)); 1963 cone[0] = 6; 1964 cone[1] = 7; 1965 cone[2] = 14; 1966 cone[3] = 13; 1967 cone[4] = 12; 1968 cone[5] = 15; 1969 cone[6] = 16; 1970 cone[7] = 11; 1971 PetscCall(DMPlexSetCone(dm, 1, cone)); 1972 cone[0] = 8; 1973 cone[1] = 17; 1974 cone[2] = 14; 1975 cone[3] = 7; 1976 cone[4] = 10; 1977 cone[5] = 11; 1978 cone[6] = 16; 1979 cone[7] = 18; 1980 PetscCall(DMPlexSetCone(dm, 2, cone)); 1981 cone[0] = 19; 1982 cone[1] = 17; 1983 cone[2] = 8; 1984 cone[3] = 5; 1985 cone[4] = 20; 1986 cone[5] = 9; 1987 cone[6] = 10; 1988 cone[7] = 18; 1989 PetscCall(DMPlexSetCone(dm, 3, cone)); 1990 cone[0] = 19; 1991 cone[1] = 5; 1992 cone[2] = 6; 1993 cone[3] = 13; 1994 cone[4] = 20; 1995 cone[5] = 15; 1996 cone[6] = 12; 1997 cone[7] = 9; 1998 PetscCall(DMPlexSetCone(dm, 4, cone)); 1999 } 2000 } 2001 PetscCall(DMPlexSymmetrize(dm)); 2002 PetscCall(DMPlexStratify(dm)); 2003 } 2004 /* Create cube geometry */ 2005 { 2006 Vec coordinates; 2007 PetscSection coordSection; 2008 PetscScalar *coords; 2009 PetscInt coordSize, v; 2010 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 2011 const PetscReal ds2 = dis / 2.0; 2012 2013 /* Build coordinates */ 2014 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2015 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2016 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2017 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2018 for (v = numCells; v < numCells + numVertices; ++v) { 2019 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2020 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2021 } 2022 PetscCall(PetscSectionSetUp(coordSection)); 2023 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2024 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2025 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2026 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2027 PetscCall(VecSetBlockSize(coordinates, dim)); 2028 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2029 PetscCall(VecGetArray(coordinates, &coords)); 2030 if (rank == 0) { 2031 coords[0 * dim + 0] = -ds2; 2032 coords[0 * dim + 1] = -ds2; 2033 coords[0 * dim + 2] = 0.0; 2034 coords[1 * dim + 0] = ds2; 2035 coords[1 * dim + 1] = -ds2; 2036 coords[1 * dim + 2] = 0.0; 2037 coords[2 * dim + 0] = ds2; 2038 coords[2 * dim + 1] = ds2; 2039 coords[2 * dim + 2] = 0.0; 2040 coords[3 * dim + 0] = -ds2; 2041 coords[3 * dim + 1] = ds2; 2042 coords[3 * dim + 2] = 0.0; 2043 coords[4 * dim + 0] = -ds2; 2044 coords[4 * dim + 1] = -ds2; 2045 coords[4 * dim + 2] = 1.0; 2046 coords[5 * dim + 0] = -ds2; 2047 coords[5 * dim + 1] = ds2; 2048 coords[5 * dim + 2] = 1.0; 2049 coords[6 * dim + 0] = ds2; 2050 coords[6 * dim + 1] = ds2; 2051 coords[6 * dim + 2] = 1.0; 2052 coords[7 * dim + 0] = ds2; 2053 coords[7 * dim + 1] = -ds2; 2054 coords[7 * dim + 2] = 1.0; 2055 coords[8 * dim + 0] = dis; 2056 coords[8 * dim + 1] = -dis; 2057 coords[8 * dim + 2] = 0.0; 2058 coords[9 * dim + 0] = dis; 2059 coords[9 * dim + 1] = dis; 2060 coords[9 * dim + 2] = 0.0; 2061 coords[10 * dim + 0] = dis; 2062 coords[10 * dim + 1] = -dis; 2063 coords[10 * dim + 2] = 1.0; 2064 coords[11 * dim + 0] = dis; 2065 coords[11 * dim + 1] = dis; 2066 coords[11 * dim + 2] = 1.0; 2067 coords[12 * dim + 0] = -dis; 2068 coords[12 * dim + 1] = dis; 2069 coords[12 * dim + 2] = 0.0; 2070 coords[13 * dim + 0] = -dis; 2071 coords[13 * dim + 1] = dis; 2072 coords[13 * dim + 2] = 1.0; 2073 coords[14 * dim + 0] = -dis; 2074 coords[14 * dim + 1] = -dis; 2075 coords[14 * dim + 2] = 0.0; 2076 coords[15 * dim + 0] = -dis; 2077 coords[15 * dim + 1] = -dis; 2078 coords[15 * dim + 2] = 1.0; 2079 if (periodicZ == DM_BOUNDARY_PERIODIC) { 2080 /* 15 31 19 */ coords[16 * dim + 0] = -ds2; 2081 coords[16 * dim + 1] = -ds2; 2082 coords[16 * dim + 2] = 0.5; 2083 /* 16 32 22 */ coords[17 * dim + 0] = ds2; 2084 coords[17 * dim + 1] = -ds2; 2085 coords[17 * dim + 2] = 0.5; 2086 /* 17 33 21 */ coords[18 * dim + 0] = ds2; 2087 coords[18 * dim + 1] = ds2; 2088 coords[18 * dim + 2] = 0.5; 2089 /* 18 34 20 */ coords[19 * dim + 0] = -ds2; 2090 coords[19 * dim + 1] = ds2; 2091 coords[19 * dim + 2] = 0.5; 2092 /* 29 35 30 */ coords[20 * dim + 0] = -dis; 2093 coords[20 * dim + 1] = -dis; 2094 coords[20 * dim + 2] = 0.5; 2095 /* 23 36 25 */ coords[21 * dim + 0] = dis; 2096 coords[21 * dim + 1] = -dis; 2097 coords[21 * dim + 2] = 0.5; 2098 /* 24 37 26 */ coords[22 * dim + 0] = dis; 2099 coords[22 * dim + 1] = dis; 2100 coords[22 * dim + 2] = 0.5; 2101 /* 27 38 28 */ coords[23 * dim + 0] = -dis; 2102 coords[23 * dim + 1] = dis; 2103 coords[23 * dim + 2] = 0.5; 2104 } 2105 } 2106 PetscCall(VecRestoreArray(coordinates, &coords)); 2107 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2108 PetscCall(VecDestroy(&coordinates)); 2109 } 2110 /* Create periodicity */ 2111 if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) { 2112 PetscReal L[3] = {-1., -1., 0.}; 2113 PetscReal maxCell[3] = {-1., -1., 0.}; 2114 PetscReal lower[3] = {0.0, 0.0, 0.0}; 2115 PetscReal upper[3] = {1.0, 1.0, 1.5}; 2116 PetscInt numZCells = 3; 2117 2118 L[2] = upper[2] - lower[2]; 2119 maxCell[2] = 1.1 * (L[2] / numZCells); 2120 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 2121 } 2122 { 2123 DM cdm; 2124 PetscDS cds; 2125 PetscScalar c[2] = {1.0, 1.0}; 2126 2127 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToCylinder)); 2128 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2129 PetscCall(DMGetDS(cdm, &cds)); 2130 PetscCall(PetscDSSetConstants(cds, 2, c)); 2131 } 2132 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 2133 2134 /* Wait for coordinate creation before doing in-place modification */ 2135 PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2136 PetscFunctionReturn(PETSC_SUCCESS); 2137 } 2138 2139 /*@ 2140 DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra. 2141 2142 Collective 2143 2144 Input Parameters: 2145 + comm - The communicator for the `DM` object 2146 - periodicZ - The boundary type for the Z direction 2147 2148 Output Parameter: 2149 . dm - The `DM` object 2150 2151 Level: beginner 2152 2153 Note: 2154 Here is the output numbering looking from the bottom of the cylinder\: 2155 .vb 2156 17-----14 2157 | | 2158 | 2 | 2159 | | 2160 17-----8-----7-----14 2161 | | | | 2162 | 3 | 0 | 1 | 2163 | | | | 2164 19-----5-----6-----13 2165 | | 2166 | 4 | 2167 | | 2168 19-----13 2169 2170 and up through the top 2171 2172 18-----16 2173 | | 2174 | 2 | 2175 | | 2176 18----10----11-----16 2177 | | | | 2178 | 3 | 0 | 1 | 2179 | | | | 2180 20-----9----12-----15 2181 | | 2182 | 4 | 2183 | | 2184 20-----15 2185 .ve 2186 2187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2188 @*/ 2189 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, DM *dm) 2190 { 2191 PetscFunctionBegin; 2192 PetscAssertPointer(dm, 3); 2193 PetscCall(DMCreate(comm, dm)); 2194 PetscCall(DMSetType(*dm, DMPLEX)); 2195 PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ)); 2196 PetscFunctionReturn(PETSC_SUCCESS); 2197 } 2198 2199 static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate) 2200 { 2201 const PetscInt dim = 3; 2202 PetscInt numCells, numVertices, v; 2203 PetscMPIInt rank; 2204 2205 PetscFunctionBegin; 2206 PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n); 2207 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 2208 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2209 PetscCall(DMSetDimension(dm, dim)); 2210 /* Must create the celltype label here so that we do not automatically try to compute the types */ 2211 PetscCall(DMCreateLabel(dm, "celltype")); 2212 /* Create topology */ 2213 { 2214 PetscInt cone[6], c; 2215 2216 numCells = rank == 0 ? n : 0; 2217 numVertices = rank == 0 ? 2 * (n + 1) : 0; 2218 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 2219 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6)); 2220 PetscCall(DMSetUp(dm)); 2221 for (c = 0; c < numCells; c++) { 2222 cone[0] = c + n * 1; 2223 cone[1] = (c + 1) % n + n * 1; 2224 cone[2] = 0 + 3 * n; 2225 cone[3] = c + n * 2; 2226 cone[4] = (c + 1) % n + n * 2; 2227 cone[5] = 1 + 3 * n; 2228 PetscCall(DMPlexSetCone(dm, c, cone)); 2229 PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR)); 2230 } 2231 PetscCall(DMPlexSymmetrize(dm)); 2232 PetscCall(DMPlexStratify(dm)); 2233 } 2234 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT)); 2235 /* Create cylinder geometry */ 2236 { 2237 Vec coordinates; 2238 PetscSection coordSection; 2239 PetscScalar *coords; 2240 PetscInt coordSize, c; 2241 2242 /* Build coordinates */ 2243 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2244 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2245 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2246 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2247 for (v = numCells; v < numCells + numVertices; ++v) { 2248 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2249 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2250 } 2251 PetscCall(PetscSectionSetUp(coordSection)); 2252 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2253 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2254 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2255 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2256 PetscCall(VecSetBlockSize(coordinates, dim)); 2257 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2258 PetscCall(VecGetArray(coordinates, &coords)); 2259 for (c = 0; c < numCells; c++) { 2260 coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 2261 coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 2262 coords[(c + 0 * n) * dim + 2] = 1.0; 2263 coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 2264 coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 2265 coords[(c + 1 * n) * dim + 2] = 0.0; 2266 } 2267 if (rank == 0) { 2268 coords[(2 * n + 0) * dim + 0] = 0.0; 2269 coords[(2 * n + 0) * dim + 1] = 0.0; 2270 coords[(2 * n + 0) * dim + 2] = 1.0; 2271 coords[(2 * n + 1) * dim + 0] = 0.0; 2272 coords[(2 * n + 1) * dim + 1] = 0.0; 2273 coords[(2 * n + 1) * dim + 2] = 0.0; 2274 } 2275 PetscCall(VecRestoreArray(coordinates, &coords)); 2276 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2277 PetscCall(VecDestroy(&coordinates)); 2278 } 2279 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 2280 /* Interpolate */ 2281 if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2282 PetscFunctionReturn(PETSC_SUCCESS); 2283 } 2284 2285 /*@ 2286 DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges. 2287 2288 Collective 2289 2290 Input Parameters: 2291 + comm - The communicator for the `DM` object 2292 . n - The number of wedges around the origin 2293 - interpolate - Create edges and faces 2294 2295 Output Parameter: 2296 . dm - The `DM` object 2297 2298 Level: beginner 2299 2300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2301 @*/ 2302 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm) 2303 { 2304 PetscFunctionBegin; 2305 PetscAssertPointer(dm, 4); 2306 PetscCall(DMCreate(comm, dm)); 2307 PetscCall(DMSetType(*dm, DMPLEX)); 2308 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate)); 2309 PetscFunctionReturn(PETSC_SUCCESS); 2310 } 2311 2312 static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 2313 { 2314 PetscReal prod = 0.0; 2315 PetscInt i; 2316 for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]); 2317 return PetscSqrtReal(prod); 2318 } 2319 static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 2320 { 2321 PetscReal prod = 0.0; 2322 PetscInt i; 2323 for (i = 0; i < dim; ++i) prod += x[i] * y[i]; 2324 return prod; 2325 } 2326 2327 /* The first constant is the sphere radius */ 2328 static void snapToSphere(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 2329 { 2330 PetscReal r = PetscRealPart(constants[0]); 2331 PetscReal norm2 = 0.0, fac; 2332 PetscInt n = uOff[1] - uOff[0], d; 2333 2334 for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d])); 2335 fac = r / PetscSqrtReal(norm2); 2336 for (d = 0; d < n; ++d) f0[d] = u[d] * fac; 2337 } 2338 2339 static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R) 2340 { 2341 const PetscInt embedDim = dim + 1; 2342 PetscSection coordSection; 2343 Vec coordinates; 2344 PetscScalar *coords; 2345 PetscReal *coordsIn; 2346 PetscInt numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e; 2347 PetscMPIInt rank; 2348 2349 PetscFunctionBegin; 2350 PetscValidLogicalCollectiveBool(dm, simplex, 3); 2351 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 2352 PetscCall(DMSetDimension(dm, dim)); 2353 PetscCall(DMSetCoordinateDim(dm, dim + 1)); 2354 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2355 switch (dim) { 2356 case 1: 2357 numCells = 16; 2358 numVerts = numCells; 2359 2360 // Build Topology 2361 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2362 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2363 PetscCall(DMSetUp(dm)); 2364 for (PetscInt c = 0; c < numCells; ++c) { 2365 PetscInt cone[2]; 2366 2367 cone[0] = c + numCells; 2368 cone[1] = (c + 1) % numVerts + numCells; 2369 PetscCall(DMPlexSetCone(dm, c, cone)); 2370 } 2371 PetscCall(DMPlexSymmetrize(dm)); 2372 PetscCall(DMPlexStratify(dm)); 2373 PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn)); 2374 for (PetscInt v = 0; v < numVerts; ++v) { 2375 const PetscReal rad = 2. * PETSC_PI * v / numVerts; 2376 2377 coordsIn[v * embedDim + 0] = PetscCosReal(rad); 2378 coordsIn[v * embedDim + 1] = PetscSinReal(rad); 2379 } 2380 break; 2381 case 2: 2382 if (simplex) { 2383 const PetscReal radius = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI); 2384 const PetscReal edgeLen = 2.0 / (1.0 + PETSC_PHI) * (R / radius); 2385 const PetscInt degree = 5; 2386 PetscReal vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)}; 2387 PetscInt s[3] = {1, 1, 1}; 2388 PetscInt cone[3]; 2389 PetscInt *graph; 2390 2391 vertex[0] *= R / radius; 2392 vertex[1] *= R / radius; 2393 vertex[2] *= R / radius; 2394 numCells = rank == 0 ? 20 : 0; 2395 numVerts = rank == 0 ? 12 : 0; 2396 firstVertex = numCells; 2397 /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of 2398 2399 (0, \pm 1/\phi+1, \pm \phi/\phi+1) 2400 2401 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 2402 length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393. 2403 */ 2404 /* Construct vertices */ 2405 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2406 if (rank == 0) { 2407 for (PetscInt p = 0, i = 0; p < embedDim; ++p) { 2408 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2409 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2410 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim]; 2411 ++i; 2412 } 2413 } 2414 } 2415 } 2416 /* Construct graph */ 2417 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 2418 for (PetscInt i = 0; i < numVerts; ++i) { 2419 PetscInt k = 0; 2420 for (PetscInt j = 0; j < numVerts; ++j) { 2421 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 2422 graph[i * numVerts + j] = 1; 2423 ++k; 2424 } 2425 } 2426 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 2427 } 2428 /* Build Topology */ 2429 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2430 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2431 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2432 /* Cells */ 2433 for (PetscInt i = 0, c = 0; i < numVerts; ++i) { 2434 for (PetscInt j = 0; j < i; ++j) { 2435 for (PetscInt k = 0; k < j; ++k) { 2436 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) { 2437 cone[0] = firstVertex + i; 2438 cone[1] = firstVertex + j; 2439 cone[2] = firstVertex + k; 2440 /* Check orientation */ 2441 { 2442 const PetscInt epsilon[3][3][3] = { 2443 {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 2444 {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 2445 {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 2446 }; 2447 PetscReal normal[3]; 2448 PetscInt e, f; 2449 2450 for (d = 0; d < embedDim; ++d) { 2451 normal[d] = 0.0; 2452 for (e = 0; e < embedDim; ++e) { 2453 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]); 2454 } 2455 } 2456 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 2457 PetscInt tmp = cone[1]; 2458 cone[1] = cone[2]; 2459 cone[2] = tmp; 2460 } 2461 } 2462 PetscCall(DMPlexSetCone(dm, c++, cone)); 2463 } 2464 } 2465 } 2466 } 2467 PetscCall(DMPlexSymmetrize(dm)); 2468 PetscCall(DMPlexStratify(dm)); 2469 PetscCall(PetscFree(graph)); 2470 } else { 2471 /* 2472 12-21--13 2473 | | 2474 25 4 24 2475 | | 2476 12-25--9-16--8-24--13 2477 | | | | 2478 23 5 17 0 15 3 22 2479 | | | | 2480 10-20--6-14--7-19--11 2481 | | 2482 20 1 19 2483 | | 2484 10-18--11 2485 | | 2486 23 2 22 2487 | | 2488 12-21--13 2489 */ 2490 PetscInt cone[4], ornt[4]; 2491 2492 numCells = rank == 0 ? 6 : 0; 2493 numEdges = rank == 0 ? 12 : 0; 2494 numVerts = rank == 0 ? 8 : 0; 2495 firstVertex = numCells; 2496 firstEdge = numCells + numVerts; 2497 /* Build Topology */ 2498 PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts)); 2499 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4)); 2500 for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 2501 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2502 if (rank == 0) { 2503 /* Cell 0 */ 2504 cone[0] = 14; 2505 cone[1] = 15; 2506 cone[2] = 16; 2507 cone[3] = 17; 2508 PetscCall(DMPlexSetCone(dm, 0, cone)); 2509 ornt[0] = 0; 2510 ornt[1] = 0; 2511 ornt[2] = 0; 2512 ornt[3] = 0; 2513 PetscCall(DMPlexSetConeOrientation(dm, 0, ornt)); 2514 /* Cell 1 */ 2515 cone[0] = 18; 2516 cone[1] = 19; 2517 cone[2] = 14; 2518 cone[3] = 20; 2519 PetscCall(DMPlexSetCone(dm, 1, cone)); 2520 ornt[0] = 0; 2521 ornt[1] = 0; 2522 ornt[2] = -1; 2523 ornt[3] = 0; 2524 PetscCall(DMPlexSetConeOrientation(dm, 1, ornt)); 2525 /* Cell 2 */ 2526 cone[0] = 21; 2527 cone[1] = 22; 2528 cone[2] = 18; 2529 cone[3] = 23; 2530 PetscCall(DMPlexSetCone(dm, 2, cone)); 2531 ornt[0] = 0; 2532 ornt[1] = 0; 2533 ornt[2] = -1; 2534 ornt[3] = 0; 2535 PetscCall(DMPlexSetConeOrientation(dm, 2, ornt)); 2536 /* Cell 3 */ 2537 cone[0] = 19; 2538 cone[1] = 22; 2539 cone[2] = 24; 2540 cone[3] = 15; 2541 PetscCall(DMPlexSetCone(dm, 3, cone)); 2542 ornt[0] = -1; 2543 ornt[1] = -1; 2544 ornt[2] = 0; 2545 ornt[3] = -1; 2546 PetscCall(DMPlexSetConeOrientation(dm, 3, ornt)); 2547 /* Cell 4 */ 2548 cone[0] = 16; 2549 cone[1] = 24; 2550 cone[2] = 21; 2551 cone[3] = 25; 2552 PetscCall(DMPlexSetCone(dm, 4, cone)); 2553 ornt[0] = -1; 2554 ornt[1] = -1; 2555 ornt[2] = -1; 2556 ornt[3] = 0; 2557 PetscCall(DMPlexSetConeOrientation(dm, 4, ornt)); 2558 /* Cell 5 */ 2559 cone[0] = 20; 2560 cone[1] = 17; 2561 cone[2] = 25; 2562 cone[3] = 23; 2563 PetscCall(DMPlexSetCone(dm, 5, cone)); 2564 ornt[0] = -1; 2565 ornt[1] = -1; 2566 ornt[2] = -1; 2567 ornt[3] = -1; 2568 PetscCall(DMPlexSetConeOrientation(dm, 5, ornt)); 2569 /* Edges */ 2570 cone[0] = 6; 2571 cone[1] = 7; 2572 PetscCall(DMPlexSetCone(dm, 14, cone)); 2573 cone[0] = 7; 2574 cone[1] = 8; 2575 PetscCall(DMPlexSetCone(dm, 15, cone)); 2576 cone[0] = 8; 2577 cone[1] = 9; 2578 PetscCall(DMPlexSetCone(dm, 16, cone)); 2579 cone[0] = 9; 2580 cone[1] = 6; 2581 PetscCall(DMPlexSetCone(dm, 17, cone)); 2582 cone[0] = 10; 2583 cone[1] = 11; 2584 PetscCall(DMPlexSetCone(dm, 18, cone)); 2585 cone[0] = 11; 2586 cone[1] = 7; 2587 PetscCall(DMPlexSetCone(dm, 19, cone)); 2588 cone[0] = 6; 2589 cone[1] = 10; 2590 PetscCall(DMPlexSetCone(dm, 20, cone)); 2591 cone[0] = 12; 2592 cone[1] = 13; 2593 PetscCall(DMPlexSetCone(dm, 21, cone)); 2594 cone[0] = 13; 2595 cone[1] = 11; 2596 PetscCall(DMPlexSetCone(dm, 22, cone)); 2597 cone[0] = 10; 2598 cone[1] = 12; 2599 PetscCall(DMPlexSetCone(dm, 23, cone)); 2600 cone[0] = 13; 2601 cone[1] = 8; 2602 PetscCall(DMPlexSetCone(dm, 24, cone)); 2603 cone[0] = 12; 2604 cone[1] = 9; 2605 PetscCall(DMPlexSetCone(dm, 25, cone)); 2606 } 2607 PetscCall(DMPlexSymmetrize(dm)); 2608 PetscCall(DMPlexStratify(dm)); 2609 /* Build coordinates */ 2610 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2611 if (rank == 0) { 2612 coordsIn[0 * embedDim + 0] = -R; 2613 coordsIn[0 * embedDim + 1] = R; 2614 coordsIn[0 * embedDim + 2] = -R; 2615 coordsIn[1 * embedDim + 0] = R; 2616 coordsIn[1 * embedDim + 1] = R; 2617 coordsIn[1 * embedDim + 2] = -R; 2618 coordsIn[2 * embedDim + 0] = R; 2619 coordsIn[2 * embedDim + 1] = -R; 2620 coordsIn[2 * embedDim + 2] = -R; 2621 coordsIn[3 * embedDim + 0] = -R; 2622 coordsIn[3 * embedDim + 1] = -R; 2623 coordsIn[3 * embedDim + 2] = -R; 2624 coordsIn[4 * embedDim + 0] = -R; 2625 coordsIn[4 * embedDim + 1] = R; 2626 coordsIn[4 * embedDim + 2] = R; 2627 coordsIn[5 * embedDim + 0] = R; 2628 coordsIn[5 * embedDim + 1] = R; 2629 coordsIn[5 * embedDim + 2] = R; 2630 coordsIn[6 * embedDim + 0] = -R; 2631 coordsIn[6 * embedDim + 1] = -R; 2632 coordsIn[6 * embedDim + 2] = R; 2633 coordsIn[7 * embedDim + 0] = R; 2634 coordsIn[7 * embedDim + 1] = -R; 2635 coordsIn[7 * embedDim + 2] = R; 2636 } 2637 } 2638 break; 2639 case 3: 2640 if (simplex) { 2641 const PetscReal edgeLen = 1.0 / PETSC_PHI; 2642 PetscReal vertexA[4] = {0.5, 0.5, 0.5, 0.5}; 2643 PetscReal vertexB[4] = {1.0, 0.0, 0.0, 0.0}; 2644 PetscReal vertexC[4] = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0}; 2645 const PetscInt degree = 12; 2646 PetscInt s[4] = {1, 1, 1}; 2647 PetscInt evenPerm[12][4] = { 2648 {0, 1, 2, 3}, 2649 {0, 2, 3, 1}, 2650 {0, 3, 1, 2}, 2651 {1, 0, 3, 2}, 2652 {1, 2, 0, 3}, 2653 {1, 3, 2, 0}, 2654 {2, 0, 1, 3}, 2655 {2, 1, 3, 0}, 2656 {2, 3, 0, 1}, 2657 {3, 0, 2, 1}, 2658 {3, 1, 0, 2}, 2659 {3, 2, 1, 0} 2660 }; 2661 PetscInt cone[4]; 2662 PetscInt *graph, p, i, j, k, l; 2663 2664 vertexA[0] *= R; 2665 vertexA[1] *= R; 2666 vertexA[2] *= R; 2667 vertexA[3] *= R; 2668 vertexB[0] *= R; 2669 vertexB[1] *= R; 2670 vertexB[2] *= R; 2671 vertexB[3] *= R; 2672 vertexC[0] *= R; 2673 vertexC[1] *= R; 2674 vertexC[2] *= R; 2675 vertexC[3] *= R; 2676 numCells = rank == 0 ? 600 : 0; 2677 numVerts = rank == 0 ? 120 : 0; 2678 firstVertex = numCells; 2679 /* Use the 600-cell, which for a unit sphere has coordinates which are 2680 2681 1/2 (\pm 1, \pm 1, \pm 1, \pm 1) 16 2682 (\pm 1, 0, 0, 0) all cyclic permutations 8 2683 1/2 (\pm 1, \pm phi, \pm 1/phi, 0) all even permutations 96 2684 2685 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 2686 length is then given by 1/\phi = 0.61803. 2687 2688 http://buzzard.pugetsound.edu/sage-practice/ch03s03.html 2689 http://mathworld.wolfram.com/600-Cell.html 2690 */ 2691 /* Construct vertices */ 2692 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2693 i = 0; 2694 if (rank == 0) { 2695 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2696 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2697 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2698 for (s[3] = -1; s[3] < 2; s[3] += 2) { 2699 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d]; 2700 ++i; 2701 } 2702 } 2703 } 2704 } 2705 for (p = 0; p < embedDim; ++p) { 2706 s[1] = s[2] = s[3] = 1; 2707 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2708 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim]; 2709 ++i; 2710 } 2711 } 2712 for (p = 0; p < 12; ++p) { 2713 s[3] = 1; 2714 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2715 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2716 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2717 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]]; 2718 ++i; 2719 } 2720 } 2721 } 2722 } 2723 } 2724 PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts); 2725 /* Construct graph */ 2726 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 2727 for (i = 0; i < numVerts; ++i) { 2728 for (j = 0, k = 0; j < numVerts; ++j) { 2729 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 2730 graph[i * numVerts + j] = 1; 2731 ++k; 2732 } 2733 } 2734 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 2735 } 2736 /* Build Topology */ 2737 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2738 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2739 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2740 /* Cells */ 2741 if (rank == 0) { 2742 for (PetscInt i = 0, c = 0; i < numVerts; ++i) { 2743 for (j = 0; j < i; ++j) { 2744 for (k = 0; k < j; ++k) { 2745 for (l = 0; l < k; ++l) { 2746 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]) { 2747 cone[0] = firstVertex + i; 2748 cone[1] = firstVertex + j; 2749 cone[2] = firstVertex + k; 2750 cone[3] = firstVertex + l; 2751 /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */ 2752 { 2753 const PetscInt epsilon[4][4][4][4] = { 2754 {{{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}}}, 2755 2756 {{{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}}}, 2757 2758 {{{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}}}, 2759 2760 {{{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}} } 2761 }; 2762 PetscReal normal[4]; 2763 PetscInt e, f, g; 2764 2765 for (d = 0; d < embedDim; ++d) { 2766 normal[d] = 0.0; 2767 for (e = 0; e < embedDim; ++e) { 2768 for (f = 0; f < embedDim; ++f) { 2769 for (g = 0; g < embedDim; ++g) { 2770 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]); 2771 } 2772 } 2773 } 2774 } 2775 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 2776 PetscInt tmp = cone[1]; 2777 cone[1] = cone[2]; 2778 cone[2] = tmp; 2779 } 2780 } 2781 PetscCall(DMPlexSetCone(dm, c++, cone)); 2782 } 2783 } 2784 } 2785 } 2786 } 2787 } 2788 PetscCall(DMPlexSymmetrize(dm)); 2789 PetscCall(DMPlexStratify(dm)); 2790 PetscCall(PetscFree(graph)); 2791 } 2792 break; 2793 default: 2794 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim); 2795 } 2796 /* Create coordinates */ 2797 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2798 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2799 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim)); 2800 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts)); 2801 for (v = firstVertex; v < firstVertex + numVerts; ++v) { 2802 PetscCall(PetscSectionSetDof(coordSection, v, embedDim)); 2803 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim)); 2804 } 2805 PetscCall(PetscSectionSetUp(coordSection)); 2806 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2807 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2808 PetscCall(VecSetBlockSize(coordinates, embedDim)); 2809 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2810 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2811 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2812 PetscCall(VecGetArray(coordinates, &coords)); 2813 for (v = 0; v < numVerts; ++v) 2814 for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d]; 2815 PetscCall(VecRestoreArray(coordinates, &coords)); 2816 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2817 PetscCall(VecDestroy(&coordinates)); 2818 PetscCall(PetscFree(coordsIn)); 2819 { 2820 DM cdm; 2821 PetscDS cds; 2822 PetscScalar c = R; 2823 2824 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToSphere)); 2825 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2826 PetscCall(DMGetDS(cdm, &cds)); 2827 PetscCall(PetscDSSetConstants(cds, 1, &c)); 2828 } 2829 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 2830 /* Wait for coordinate creation before doing in-place modification */ 2831 if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2832 PetscFunctionReturn(PETSC_SUCCESS); 2833 } 2834 2835 typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]); 2836 2837 /* 2838 The Schwarz P implicit surface is 2839 2840 f(x) = cos(x0) + cos(x1) + cos(x2) = 0 2841 */ 2842 static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 2843 { 2844 PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)}; 2845 PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)}; 2846 f[0] = c[0] + c[1] + c[2]; 2847 for (PetscInt i = 0; i < 3; i++) { 2848 grad[i] = PETSC_PI * g[i]; 2849 for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.; 2850 } 2851 } 2852 2853 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 2854 static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 2855 { 2856 for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI); 2857 return PETSC_SUCCESS; 2858 } 2859 2860 /* 2861 The Gyroid implicit surface is 2862 2863 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) 2864 2865 */ 2866 static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 2867 { 2868 PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))}; 2869 PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))}; 2870 f[0] = s[0] * c[1] + s[1] * c[2] + s[2] * c[0]; 2871 grad[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 2872 grad[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 2873 grad[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 2874 hess[0][0] = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]); 2875 hess[0][1] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 2876 hess[0][2] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 2877 hess[1][0] = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]); 2878 hess[1][1] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 2879 hess[2][2] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 2880 hess[2][0] = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]); 2881 hess[2][1] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 2882 hess[2][2] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 2883 } 2884 2885 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 2886 static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 2887 { 2888 PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))}; 2889 PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))}; 2890 u[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 2891 u[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 2892 u[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 2893 return PETSC_SUCCESS; 2894 } 2895 2896 /* 2897 We wish to solve 2898 2899 min_y || y - x ||^2 subject to f(y) = 0 2900 2901 Let g(y) = grad(f). The minimization problem is equivalent to asking to satisfy 2902 f(y) = 0 and (y-x) is parallel to g(y). We do this by using Householder QR to obtain a basis for the 2903 tangent space and ask for both components in the tangent space to be zero. 2904 2905 Take g to be a column vector and compute the "full QR" factorization Q R = g, 2906 where Q = I - 2 n n^T is a symmetric orthogonal matrix. 2907 The first column of Q is parallel to g so the remaining two columns span the null space. 2908 Let Qn = Q[:,1:] be those remaining columns. Then Qn Qn^T is an orthogonal projector into the tangent space. 2909 Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries. 2910 In total, we have a system of 3 equations in 3 unknowns: 2911 2912 f(y) = 0 1 equation 2913 Qn^T (y - x) = 0 2 equations 2914 2915 Here, we compute the residual and Jacobian of this system. 2916 */ 2917 static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[]) 2918 { 2919 PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])}; 2920 PetscReal d[3] = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])}; 2921 PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign; 2922 PetscReal n_y[3][3] = { 2923 {0, 0, 0}, 2924 {0, 0, 0}, 2925 {0, 0, 0} 2926 }; 2927 2928 feval(yreal, &f, grad, n_y); 2929 2930 for (PetscInt i = 0; i < 3; i++) n[i] = grad[i]; 2931 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 2932 for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i]; 2933 2934 // Define the Householder reflector 2935 sign = n[0] >= 0 ? 1. : -1.; 2936 n[0] += norm * sign; 2937 for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign; 2938 2939 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 2940 norm_y[0] = 1. / norm * (n[0] * n_y[0][0]); 2941 norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]); 2942 norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]); 2943 2944 for (PetscInt i = 0; i < 3; i++) { 2945 n[i] /= norm; 2946 for (PetscInt j = 0; j < 3; j++) { 2947 // note that n[i] is n_old[i]/norm when executing the code below 2948 n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j]; 2949 } 2950 } 2951 2952 nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2]; 2953 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]; 2954 2955 res[0] = f; 2956 res[1] = d[1] - 2 * n[1] * nd; 2957 res[2] = d[2] - 2 * n[2] * nd; 2958 // J[j][i] is J_{ij} (column major) 2959 for (PetscInt j = 0; j < 3; j++) { 2960 J[0 + j * 3] = grad[j]; 2961 J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]); 2962 J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]); 2963 } 2964 } 2965 2966 /* 2967 Project x to the nearest point on the implicit surface using Newton's method. 2968 */ 2969 static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[]) 2970 { 2971 PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess 2972 2973 PetscFunctionBegin; 2974 for (PetscInt iter = 0; iter < 10; iter++) { 2975 PetscScalar res[3], J[9]; 2976 PetscReal resnorm; 2977 TPSNearestPointResJac(feval, x, y, res, J); 2978 resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2]))); 2979 if (0) { // Turn on this monitor if you need to confirm quadratic convergence 2980 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]))); 2981 } 2982 if (resnorm < PETSC_SMALL) break; 2983 2984 // Take the Newton step 2985 PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL)); 2986 PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res); 2987 } 2988 for (PetscInt i = 0; i < 3; i++) x[i] = y[i]; 2989 PetscFunctionReturn(PETSC_SUCCESS); 2990 } 2991 2992 const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL}; 2993 2994 static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness) 2995 { 2996 PetscMPIInt rank; 2997 PetscInt topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0; 2998 PetscInt(*edges)[2] = NULL, *edgeSets = NULL; 2999 PetscInt *cells_flat = NULL; 3000 PetscReal *vtxCoords = NULL; 3001 TPSEvaluateFunc evalFunc = NULL; 3002 PetscSimplePointFunc normalFunc = NULL; 3003 DMLabel label; 3004 3005 PetscFunctionBegin; 3006 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 3007 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3008 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); 3009 switch (tpstype) { 3010 case DMPLEX_TPS_SCHWARZ_P: 3011 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"); 3012 if (rank == 0) { 3013 PetscInt(*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn] 3014 PetscInt Njunctions = 0, Ncuts = 0, Npipes[3], vcount; 3015 PetscReal L = 1; 3016 3017 Npipes[0] = (extent[0] + 1) * extent[1] * extent[2]; 3018 Npipes[1] = extent[0] * (extent[1] + 1) * extent[2]; 3019 Npipes[2] = extent[0] * extent[1] * (extent[2] + 1); 3020 Njunctions = extent[0] * extent[1] * extent[2]; 3021 Ncuts = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]); 3022 numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions; 3023 PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords)); 3024 PetscCall(PetscMalloc1(Njunctions, &cells)); 3025 PetscCall(PetscMalloc1(Ncuts * 4, &edges)); 3026 PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets)); 3027 // x-normal pipes 3028 vcount = 0; 3029 for (PetscInt i = 0; i < extent[0] + 1; i++) { 3030 for (PetscInt j = 0; j < extent[1]; j++) { 3031 for (PetscInt k = 0; k < extent[2]; k++) { 3032 for (PetscInt l = 0; l < 4; l++) { 3033 vtxCoords[vcount++] = (2 * i - 1) * L; 3034 vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3035 vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3036 } 3037 } 3038 } 3039 } 3040 // y-normal pipes 3041 for (PetscInt i = 0; i < extent[0]; i++) { 3042 for (PetscInt j = 0; j < extent[1] + 1; j++) { 3043 for (PetscInt k = 0; k < extent[2]; k++) { 3044 for (PetscInt l = 0; l < 4; l++) { 3045 vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3046 vtxCoords[vcount++] = (2 * j - 1) * L; 3047 vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3048 } 3049 } 3050 } 3051 } 3052 // z-normal pipes 3053 for (PetscInt i = 0; i < extent[0]; i++) { 3054 for (PetscInt j = 0; j < extent[1]; j++) { 3055 for (PetscInt k = 0; k < extent[2] + 1; k++) { 3056 for (PetscInt l = 0; l < 4; l++) { 3057 vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3058 vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3059 vtxCoords[vcount++] = (2 * k - 1) * L; 3060 } 3061 } 3062 } 3063 } 3064 // junctions 3065 for (PetscInt i = 0; i < extent[0]; i++) { 3066 for (PetscInt j = 0; j < extent[1]; j++) { 3067 for (PetscInt k = 0; k < extent[2]; k++) { 3068 const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8; 3069 PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count"); 3070 for (PetscInt ii = 0; ii < 2; ii++) { 3071 for (PetscInt jj = 0; jj < 2; jj++) { 3072 for (PetscInt kk = 0; kk < 2; kk++) { 3073 double Ls = (1 - sqrt(2) / 4) * L; 3074 vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls; 3075 vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls; 3076 vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls; 3077 } 3078 } 3079 } 3080 const PetscInt jfaces[3][2][4] = { 3081 {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned 3082 {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned 3083 {{6, 2, 0, 4}, {7, 3, 1, 5}} // z-aligned 3084 }; 3085 const PetscInt pipe_lo[3] = {// vertex numbers of pipes 3086 ((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}; 3087 const PetscInt pipe_hi[3] = {// vertex numbers of pipes 3088 (((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}; 3089 for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z 3090 const PetscInt ijk[3] = {i, j, k}; 3091 for (PetscInt l = 0; l < 4; l++) { // rotations 3092 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l; 3093 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l]; 3094 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4]; 3095 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4; 3096 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l]; 3097 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l; 3098 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4; 3099 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4]; 3100 if (ijk[dir] == 0) { 3101 edges[numEdges][0] = pipe_lo[dir] + l; 3102 edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4; 3103 edgeSets[numEdges] = dir * 2 + 1; 3104 numEdges++; 3105 } 3106 if (ijk[dir] + 1 == extent[dir]) { 3107 edges[numEdges][0] = pipe_hi[dir] + l; 3108 edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4; 3109 edgeSets[numEdges] = dir * 2 + 2; 3110 numEdges++; 3111 } 3112 } 3113 } 3114 } 3115 } 3116 } 3117 PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts); 3118 numFaces = 24 * Njunctions; 3119 cells_flat = cells[0][0][0]; 3120 } 3121 evalFunc = TPSEvaluate_SchwarzP; 3122 normalFunc = TPSExtrudeNormalFunc_SchwarzP; 3123 break; 3124 case DMPLEX_TPS_GYROID: 3125 if (rank == 0) { 3126 // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set 3127 // 3128 // 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) 3129 // 3130 // on the cell [0,2]^3. 3131 // 3132 // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2]. 3133 // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins 3134 // like a boomerang: 3135 // 3136 // z = 0 z = 1/4 z = 1/2 z = 3/4 // 3137 // ----- ------- ------- ------- // 3138 // // 3139 // + + + + + + + \ + // 3140 // \ / \ // 3141 // \ `-_ _-' / } // 3142 // *-_ `-' _-' / // 3143 // + `-+ + + +-' + + / + // 3144 // // 3145 // // 3146 // z = 1 z = 5/4 z = 3/2 z = 7/4 // 3147 // ----- ------- ------- ------- // 3148 // // 3149 // +-_ + + + + _-+ + / + // 3150 // `-_ _-_ _-` / // 3151 // \ _-' `-_ / { // 3152 // \ / \ // 3153 // + + + + + + + \ + // 3154 // 3155 // 3156 // This course mesh approximates each of these slices by two line segments, 3157 // and then connects the segments in consecutive layers with quadrilateral faces. 3158 // All of the end points of the segments are multiples of 1/4 except for the 3159 // point * in the picture for z = 0 above and the similar points in other layers. 3160 // That point is at (gamma, gamma, 0), where gamma is calculated below. 3161 // 3162 // The column [1,2]x[1,2]x[0,2] looks the same as this column; 3163 // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images. 3164 // 3165 // As for how this method turned into the names given to the vertices: 3166 // that was not systematic, it was just the way it worked out in my handwritten notes. 3167 3168 PetscInt facesPerBlock = 64; 3169 PetscInt vertsPerBlock = 56; 3170 PetscInt extentPlus[3]; 3171 PetscInt numBlocks, numBlocksPlus; 3172 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; 3173 const PetscInt pattern[64][4] = { 3174 /* face to vertex within the coarse discretization of a single gyroid block */ 3175 /* layer 0 */ 3176 {A, C, K, G }, 3177 {C, B, II, K }, 3178 {D, A, H, L }, 3179 {B + 56 * 1, D, L, J }, 3180 {E, B + 56 * 1, J, N }, 3181 {A + 56 * 2, E, N, H + 56 * 2 }, 3182 {F, A + 56 * 2, G + 56 * 2, M }, 3183 {B, F, M, II }, 3184 /* layer 1 */ 3185 {G, K, Q, O }, 3186 {K, II, P, Q }, 3187 {L, H, O + 56 * 1, R }, 3188 {J, L, R, P }, 3189 {N, J, P, S }, 3190 {H + 56 * 2, N, S, O + 56 * 3 }, 3191 {M, G + 56 * 2, O + 56 * 2, T }, 3192 {II, M, T, P }, 3193 /* layer 2 */ 3194 {O, Q, Y, U }, 3195 {Q, P, W, Y }, 3196 {R, O + 56 * 1, U + 56 * 1, Ap }, 3197 {P, R, Ap, W }, 3198 {S, P, X, Bp }, 3199 {O + 56 * 3, S, Bp, V + 56 * 1 }, 3200 {T, O + 56 * 2, V, Z }, 3201 {P, T, Z, X }, 3202 /* layer 3 */ 3203 {U, Y, Ep, Dp }, 3204 {Y, W, Cp, Ep }, 3205 {Ap, U + 56 * 1, Dp + 56 * 1, Gp }, 3206 {W, Ap, Gp, Cp }, 3207 {Bp, X, Cp + 56 * 2, Fp }, 3208 {V + 56 * 1, Bp, Fp, Dp + 56 * 1}, 3209 {Z, V, Dp, Hp }, 3210 {X, Z, Hp, Cp + 56 * 2}, 3211 /* layer 4 */ 3212 {Dp, Ep, Mp, Kp }, 3213 {Ep, Cp, Ip, Mp }, 3214 {Gp, Dp + 56 * 1, Lp, Np }, 3215 {Cp, Gp, Np, Jp }, 3216 {Fp, Cp + 56 * 2, Jp + 56 * 2, Pp }, 3217 {Dp + 56 * 1, Fp, Pp, Lp }, 3218 {Hp, Dp, Kp, Op }, 3219 {Cp + 56 * 2, Hp, Op, Ip + 56 * 2}, 3220 /* layer 5 */ 3221 {Kp, Mp, Sp, Rp }, 3222 {Mp, Ip, Qp, Sp }, 3223 {Np, Lp, Rp, Tp }, 3224 {Jp, Np, Tp, Qp + 56 * 1}, 3225 {Pp, Jp + 56 * 2, Qp + 56 * 3, Up }, 3226 {Lp, Pp, Up, Rp }, 3227 {Op, Kp, Rp, Vp }, 3228 {Ip + 56 * 2, Op, Vp, Qp + 56 * 2}, 3229 /* layer 6 */ 3230 {Rp, Sp, Aq, Yp }, 3231 {Sp, Qp, Wp, Aq }, 3232 {Tp, Rp, Yp, Cq }, 3233 {Qp + 56 * 1, Tp, Cq, Wp + 56 * 1}, 3234 {Up, Qp + 56 * 3, Xp + 56 * 1, Dq }, 3235 {Rp, Up, Dq, Zp }, 3236 {Vp, Rp, Zp, Bq }, 3237 {Qp + 56 * 2, Vp, Bq, Xp }, 3238 /* layer 7 (the top is the periodic image of the bottom of layer 0) */ 3239 {Yp, Aq, C + 56 * 4, A + 56 * 4 }, 3240 {Aq, Wp, B + 56 * 4, C + 56 * 4 }, 3241 {Cq, Yp, A + 56 * 4, D + 56 * 4 }, 3242 {Wp + 56 * 1, Cq, D + 56 * 4, B + 56 * 5 }, 3243 {Dq, Xp + 56 * 1, B + 56 * 5, E + 56 * 4 }, 3244 {Zp, Dq, E + 56 * 4, A + 56 * 6 }, 3245 {Bq, Zp, A + 56 * 6, F + 56 * 4 }, 3246 {Xp, Bq, F + 56 * 4, B + 56 * 4 } 3247 }; 3248 const PetscReal gamma = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI; 3249 const PetscReal patternCoords[56][3] = { 3250 {1., 0., 0. }, /* A */ 3251 {0., 1., 0. }, /* B */ 3252 {gamma, gamma, 0. }, /* C */ 3253 {1 + gamma, 1 - gamma, 0. }, /* D */ 3254 {2 - gamma, 2 - gamma, 0. }, /* E */ 3255 {1 - gamma, 1 + gamma, 0. }, /* F */ 3256 3257 {.5, 0, .25 }, /* G */ 3258 {1.5, 0., .25 }, /* H */ 3259 {.5, 1., .25 }, /* II */ 3260 {1.5, 1., .25 }, /* J */ 3261 {.25, .5, .25 }, /* K */ 3262 {1.25, .5, .25 }, /* L */ 3263 {.75, 1.5, .25 }, /* M */ 3264 {1.75, 1.5, .25 }, /* N */ 3265 3266 {0., 0., .5 }, /* O */ 3267 {1., 1., .5 }, /* P */ 3268 {gamma, 1 - gamma, .5 }, /* Q */ 3269 {1 + gamma, gamma, .5 }, /* R */ 3270 {2 - gamma, 1 + gamma, .5 }, /* S */ 3271 {1 - gamma, 2 - gamma, .5 }, /* T */ 3272 3273 {0., .5, .75 }, /* U */ 3274 {0., 1.5, .75 }, /* V */ 3275 {1., .5, .75 }, /* W */ 3276 {1., 1.5, .75 }, /* X */ 3277 {.5, .75, .75 }, /* Y */ 3278 {.5, 1.75, .75 }, /* Z */ 3279 {1.5, .25, .75 }, /* Ap */ 3280 {1.5, 1.25, .75 }, /* Bp */ 3281 3282 {1., 0., 1. }, /* Cp */ 3283 {0., 1., 1. }, /* Dp */ 3284 {1 - gamma, 1 - gamma, 1. }, /* Ep */ 3285 {1 + gamma, 1 + gamma, 1. }, /* Fp */ 3286 {2 - gamma, gamma, 1. }, /* Gp */ 3287 {gamma, 2 - gamma, 1. }, /* Hp */ 3288 3289 {.5, 0., 1.25}, /* Ip */ 3290 {1.5, 0., 1.25}, /* Jp */ 3291 {.5, 1., 1.25}, /* Kp */ 3292 {1.5, 1., 1.25}, /* Lp */ 3293 {.75, .5, 1.25}, /* Mp */ 3294 {1.75, .5, 1.25}, /* Np */ 3295 {.25, 1.5, 1.25}, /* Op */ 3296 {1.25, 1.5, 1.25}, /* Pp */ 3297 3298 {0., 0., 1.5 }, /* Qp */ 3299 {1., 1., 1.5 }, /* Rp */ 3300 {1 - gamma, gamma, 1.5 }, /* Sp */ 3301 {2 - gamma, 1 - gamma, 1.5 }, /* Tp */ 3302 {1 + gamma, 2 - gamma, 1.5 }, /* Up */ 3303 {gamma, 1 + gamma, 1.5 }, /* Vp */ 3304 3305 {0., .5, 1.75}, /* Wp */ 3306 {0., 1.5, 1.75}, /* Xp */ 3307 {1., .5, 1.75}, /* Yp */ 3308 {1., 1.5, 1.75}, /* Zp */ 3309 {.5, .25, 1.75}, /* Aq */ 3310 {.5, 1.25, 1.75}, /* Bq */ 3311 {1.5, .75, 1.75}, /* Cq */ 3312 {1.5, 1.75, 1.75}, /* Dq */ 3313 }; 3314 PetscInt(*cells)[64][4] = NULL; 3315 PetscBool *seen; 3316 PetscInt *vertToTrueVert; 3317 PetscInt count; 3318 3319 for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1; 3320 numBlocks = 1; 3321 for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i]; 3322 numBlocksPlus = 1; 3323 for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i]; 3324 numFaces = numBlocks * facesPerBlock; 3325 PetscCall(PetscMalloc1(numBlocks, &cells)); 3326 PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen)); 3327 for (PetscInt k = 0; k < extent[2]; k++) { 3328 for (PetscInt j = 0; j < extent[1]; j++) { 3329 for (PetscInt i = 0; i < extent[0]; i++) { 3330 for (PetscInt f = 0; f < facesPerBlock; f++) { 3331 for (PetscInt v = 0; v < 4; v++) { 3332 PetscInt vertRaw = pattern[f][v]; 3333 PetscInt blockidx = vertRaw / 56; 3334 PetscInt patternvert = vertRaw % 56; 3335 PetscInt xplus = (blockidx & 1); 3336 PetscInt yplus = (blockidx & 2) >> 1; 3337 PetscInt zplus = (blockidx & 4) >> 2; 3338 PetscInt zcoord = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus); 3339 PetscInt ycoord = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus); 3340 PetscInt xcoord = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus); 3341 PetscInt vert = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert; 3342 3343 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert; 3344 seen[vert] = PETSC_TRUE; 3345 } 3346 } 3347 } 3348 } 3349 } 3350 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) 3351 if (seen[i]) numVertices++; 3352 count = 0; 3353 PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert)); 3354 PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords)); 3355 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1; 3356 for (PetscInt k = 0; k < extentPlus[2]; k++) { 3357 for (PetscInt j = 0; j < extentPlus[1]; j++) { 3358 for (PetscInt i = 0; i < extentPlus[0]; i++) { 3359 for (PetscInt v = 0; v < vertsPerBlock; v++) { 3360 PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v; 3361 3362 if (seen[vIdx]) { 3363 PetscInt thisVert; 3364 3365 vertToTrueVert[vIdx] = thisVert = count++; 3366 3367 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d]; 3368 vtxCoords[3 * thisVert + 0] += i * 2; 3369 vtxCoords[3 * thisVert + 1] += j * 2; 3370 vtxCoords[3 * thisVert + 2] += k * 2; 3371 } 3372 } 3373 } 3374 } 3375 } 3376 for (PetscInt i = 0; i < numBlocks; i++) { 3377 for (PetscInt f = 0; f < facesPerBlock; f++) { 3378 for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]]; 3379 } 3380 } 3381 PetscCall(PetscFree(vertToTrueVert)); 3382 PetscCall(PetscFree(seen)); 3383 cells_flat = cells[0][0]; 3384 numEdges = 0; 3385 for (PetscInt i = 0; i < numFaces; i++) { 3386 for (PetscInt e = 0; e < 4; e++) { 3387 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 3388 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 3389 3390 for (PetscInt d = 0; d < 3; d++) { 3391 if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) { 3392 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++; 3393 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++; 3394 } 3395 } 3396 } 3397 } 3398 PetscCall(PetscMalloc1(numEdges, &edges)); 3399 PetscCall(PetscMalloc1(numEdges, &edgeSets)); 3400 for (PetscInt edge = 0, i = 0; i < numFaces; i++) { 3401 for (PetscInt e = 0; e < 4; e++) { 3402 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 3403 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 3404 3405 for (PetscInt d = 0; d < 3; d++) { 3406 if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) { 3407 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) { 3408 edges[edge][0] = ev[0]; 3409 edges[edge][1] = ev[1]; 3410 edgeSets[edge++] = 2 * d; 3411 } 3412 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) { 3413 edges[edge][0] = ev[0]; 3414 edges[edge][1] = ev[1]; 3415 edgeSets[edge++] = 2 * d + 1; 3416 } 3417 } 3418 } 3419 } 3420 } 3421 } 3422 evalFunc = TPSEvaluate_Gyroid; 3423 normalFunc = TPSExtrudeNormalFunc_Gyroid; 3424 break; 3425 } 3426 3427 PetscCall(DMSetDimension(dm, topoDim)); 3428 if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat)); 3429 else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL)); 3430 PetscCall(PetscFree(cells_flat)); 3431 { 3432 DM idm; 3433 PetscCall(DMPlexInterpolate(dm, &idm)); 3434 PetscCall(DMPlexReplace_Internal(dm, &idm)); 3435 } 3436 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords)); 3437 else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL)); 3438 PetscCall(PetscFree(vtxCoords)); 3439 3440 PetscCall(DMCreateLabel(dm, "Face Sets")); 3441 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 3442 for (PetscInt e = 0; e < numEdges; e++) { 3443 PetscInt njoin; 3444 const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]}; 3445 PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join)); 3446 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]); 3447 PetscCall(DMLabelSetValue(label, join[0], edgeSets[e])); 3448 PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join)); 3449 } 3450 PetscCall(PetscFree(edges)); 3451 PetscCall(PetscFree(edgeSets)); 3452 if (tps_distribute) { 3453 DM pdm = NULL; 3454 PetscPartitioner part; 3455 3456 PetscCall(DMPlexGetPartitioner(dm, &part)); 3457 PetscCall(PetscPartitionerSetFromOptions(part)); 3458 PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm)); 3459 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 3460 // Do not auto-distribute again 3461 PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE)); 3462 } 3463 3464 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 3465 for (PetscInt refine = 0; refine < refinements; refine++) { 3466 PetscInt m; 3467 DM dmf; 3468 Vec X; 3469 PetscScalar *x; 3470 PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf)); 3471 PetscCall(DMPlexReplace_Internal(dm, &dmf)); 3472 3473 PetscCall(DMGetCoordinatesLocal(dm, &X)); 3474 PetscCall(VecGetLocalSize(X, &m)); 3475 PetscCall(VecGetArray(X, &x)); 3476 for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i])); 3477 PetscCall(VecRestoreArray(X, &x)); 3478 } 3479 3480 // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices. 3481 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 3482 PetscCall(DMPlexLabelComplete(dm, label)); 3483 3484 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 3485 3486 if (thickness > 0) { 3487 DM edm, cdm, ecdm; 3488 DMPlexTransform tr; 3489 const char *prefix; 3490 PetscOptions options; 3491 // Code from DMPlexExtrude 3492 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 3493 PetscCall(DMPlexTransformSetDM(tr, dm)); 3494 PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDE)); 3495 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 3496 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 3497 PetscCall(PetscObjectGetOptions((PetscObject)dm, &options)); 3498 PetscCall(PetscObjectSetOptions((PetscObject)tr, options)); 3499 PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers)); 3500 PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness)); 3501 PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE)); 3502 PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE)); 3503 PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc)); 3504 PetscCall(DMPlexTransformSetFromOptions(tr)); 3505 PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL)); 3506 PetscCall(DMPlexTransformSetUp(tr)); 3507 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view")); 3508 PetscCall(DMPlexTransformApply(tr, dm, &edm)); 3509 PetscCall(DMCopyDisc(dm, edm)); 3510 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3511 PetscCall(DMGetCoordinateDM(edm, &ecdm)); 3512 PetscCall(DMCopyDisc(cdm, ecdm)); 3513 PetscCall(DMPlexTransformCreateDiscLabels(tr, edm)); 3514 PetscCall(DMPlexTransformDestroy(&tr)); 3515 if (edm) { 3516 ((DM_Plex *)edm->data)->printFEM = ((DM_Plex *)dm->data)->printFEM; 3517 ((DM_Plex *)edm->data)->printL2 = ((DM_Plex *)dm->data)->printL2; 3518 ((DM_Plex *)edm->data)->printLocate = ((DM_Plex *)dm->data)->printLocate; 3519 } 3520 PetscCall(DMPlexReplace_Internal(dm, &edm)); 3521 } 3522 PetscFunctionReturn(PETSC_SUCCESS); 3523 } 3524 3525 /*@ 3526 DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface 3527 3528 Collective 3529 3530 Input Parameters: 3531 + comm - The communicator for the `DM` object 3532 . tpstype - Type of triply-periodic surface 3533 . extent - Array of length 3 containing number of periods in each direction 3534 . periodic - array of length 3 with periodicity, or `NULL` for non-periodic 3535 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable) 3536 . refinements - Number of factor-of-2 refinements of 2D manifold mesh 3537 . layers - Number of cell layers extruded in normal direction 3538 - thickness - Thickness in normal direction 3539 3540 Output Parameter: 3541 . dm - The `DM` object 3542 3543 Level: beginner 3544 3545 Notes: 3546 This meshes the surface of the Schwarz P or Gyroid surfaces. Schwarz P is is the simplest member of the triply-periodic minimal surfaces. 3547 https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22) and can be cut with "clean" boundaries. 3548 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. 3549 Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested. 3550 On each refinement, all vertices are projected to their nearest point on the surface. 3551 This projection could readily be extended to related surfaces. 3552 3553 The face (edge) sets for the Schwarz P surface are numbered 1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z). 3554 When the mesh is refined, "Face Sets" contain the new vertices (created during refinement). Use `DMPlexLabelComplete()` to propagate to coarse-level vertices. 3555 3556 Developer Notes: 3557 The Gyroid mesh does not currently mark boundary sets. 3558 3559 References: 3560 . * - Maskery et al, Insights into the mechanical properties of several triply periodic minimal surface lattice structures made by polymer additive manufacturing, 2017. 3561 https://doi.org/10.1016/j.polymer.2017.11.049 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