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