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