1 #define PETSCDM_DLL 2 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 3 #include <petsc/private/hashseti.h> 4 #include <petscsf.h> 5 #include <petscdmplextransform.h> /*I "petscdmplextransform.h" I*/ 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 /*@ 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 const char *name; 3926 3927 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 3928 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, nameflg ? plexname : name, interpolate, &dmnew)); 3929 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3930 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3931 } else if (refDomain) { 3932 PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell)); 3933 } else if (bdfflg) { 3934 DM bdm, dmnew; 3935 const char *name; 3936 3937 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 3938 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, nameflg ? plexname : name, interpolate, &bdm)); 3939 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_")); 3940 PetscCall(DMSetFromOptions(bdm)); 3941 PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew)); 3942 PetscCall(DMDestroy(&bdm)); 3943 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3944 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3945 } else if (strflg) { 3946 DM dmnew; 3947 PetscViewer viewer; 3948 const char *contents; 3949 char *strname; 3950 char tmpdir[PETSC_MAX_PATH_LEN]; 3951 char tmpfilename[PETSC_MAX_PATH_LEN]; 3952 char name[PETSC_MAX_PATH_LEN]; 3953 MPI_Comm comm; 3954 PetscMPIInt rank; 3955 3956 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3957 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 3958 PetscCall(PetscStrchr(filename, ':', &strname)); 3959 PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename); 3960 strname[0] = '\0'; 3961 ++strname; 3962 PetscCall(PetscDLSym(NULL, strname, (void **)&contents)); 3963 PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname); 3964 PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN)); 3965 PetscCall(PetscStrlcat(tmpdir, "/meshXXXXXX", PETSC_MAX_PATH_LEN)); 3966 PetscCall(PetscMkdtemp(tmpdir)); 3967 PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh.%s", tmpdir, filename)); 3968 PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer)); 3969 PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents)); 3970 PetscCall(PetscViewerDestroy(&viewer)); 3971 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew)); 3972 PetscCall(PetscRMTree(tmpdir)); 3973 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname)); 3974 PetscCall(PetscObjectSetName((PetscObject)dm, name)); 3975 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 3976 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 3977 } else { 3978 PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape])); 3979 switch (shape) { 3980 case DM_SHAPE_BOX: 3981 case DM_SHAPE_ZBOX: 3982 case DM_SHAPE_ANNULUS: { 3983 PetscInt faces[3] = {0, 0, 0}; 3984 PetscReal lower[3] = {0, 0, 0}; 3985 PetscReal upper[3] = {1, 1, 1}; 3986 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 3987 PetscBool isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE; 3988 PetscInt i, n; 3989 3990 n = dim; 3991 for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim); 3992 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 3993 n = 3; 3994 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 3995 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3996 n = 3; 3997 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 3998 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 3999 n = 3; 4000 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4001 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4002 4003 PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented"); 4004 if (isAnnular) 4005 for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC; 4006 4007 switch (cell) { 4008 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4009 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt)); 4010 if (!interpolate) { 4011 DM udm; 4012 4013 PetscCall(DMPlexUninterpolate(dm, &udm)); 4014 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4015 } 4016 break; 4017 default: 4018 PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate)); 4019 break; 4020 } 4021 if (isAnnular) { 4022 DM cdm; 4023 PetscDS cds; 4024 PetscScalar bounds[2] = {lower[0], upper[0]}; 4025 4026 // Fix coordinates for annular region 4027 PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 4028 PetscCall(DMSetCellCoordinatesLocal(dm, NULL)); 4029 PetscCall(DMSetCellCoordinates(dm, NULL)); 4030 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 4031 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4032 PetscCall(DMGetDS(cdm, &cds)); 4033 PetscCall(PetscDSSetConstants(cds, 2, bounds)); 4034 PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus)); 4035 } 4036 } break; 4037 case DM_SHAPE_BOX_SURFACE: { 4038 PetscInt faces[3] = {0, 0, 0}; 4039 PetscReal lower[3] = {0, 0, 0}; 4040 PetscReal upper[3] = {1, 1, 1}; 4041 PetscInt i, n; 4042 4043 n = dim + 1; 4044 for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1)); 4045 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4046 n = 3; 4047 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4048 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); 4049 n = 3; 4050 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4051 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); 4052 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate)); 4053 } break; 4054 case DM_SHAPE_SPHERE: { 4055 PetscReal R = 1.0; 4056 4057 PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg)); 4058 PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R)); 4059 } break; 4060 case DM_SHAPE_BALL: { 4061 PetscReal R = 1.0; 4062 4063 PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg)); 4064 PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R)); 4065 } break; 4066 case DM_SHAPE_CYLINDER: { 4067 DMBoundaryType bdt = DM_BOUNDARY_NONE; 4068 PetscInt Nw = 6; 4069 4070 PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL)); 4071 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL)); 4072 switch (cell) { 4073 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4074 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate)); 4075 break; 4076 default: 4077 PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt)); 4078 break; 4079 } 4080 } break; 4081 case DM_SHAPE_SCHWARZ_P: // fallthrough 4082 case DM_SHAPE_GYROID: { 4083 PetscInt extent[3] = {1, 1, 1}, refine = 0, layers = 0, three; 4084 PetscReal thickness = 0.; 4085 DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4086 DMPlexTPSType tps_type = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID; 4087 PetscBool tps_distribute; 4088 PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL)); 4089 PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL)); 4090 PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL)); 4091 PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL)); 4092 PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL)); 4093 PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute)); 4094 PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL)); 4095 PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness)); 4096 } break; 4097 case DM_SHAPE_DOUBLET: { 4098 DM dmnew; 4099 PetscReal rl = 0.0; 4100 4101 PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL)); 4102 PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew)); 4103 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4104 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4105 } break; 4106 case DM_SHAPE_HYPERCUBIC: { 4107 PetscInt *edges; 4108 PetscReal *lower, *upper; 4109 DMBoundaryType *bdt; 4110 PetscInt n, d; 4111 4112 *useCoordSpace = PETSC_FALSE; 4113 PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt)); 4114 for (d = 0; d < dim; ++d) { 4115 edges[d] = 1; 4116 lower[d] = 0.; 4117 upper[d] = 1.; 4118 bdt[d] = DM_BOUNDARY_PERIODIC; 4119 } 4120 n = dim; 4121 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg)); 4122 n = dim; 4123 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4124 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4125 n = dim; 4126 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4127 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4128 n = dim; 4129 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4130 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4131 PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt)); 4132 PetscCall(PetscFree4(edges, lower, upper, bdt)); 4133 } break; 4134 default: 4135 SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]); 4136 } 4137 } 4138 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4139 if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname)); 4140 // Allow label creation 4141 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg)); 4142 if (flg) { 4143 DMLabel label; 4144 PetscInt points[1024], n = 1024; 4145 char fulloption[PETSC_MAX_PATH_LEN]; 4146 const char *name = &option[14]; 4147 4148 PetscCall(DMCreateLabel(dm, name)); 4149 PetscCall(DMGetLabel(dm, name, &label)); 4150 fulloption[0] = '-'; 4151 fulloption[1] = 0; 4152 PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN)); 4153 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL)); 4154 for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1)); 4155 } 4156 // Allow cohesive label creation 4157 // Faces are input, completed, and all points are marked with their depth 4158 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg)); 4159 if (flg) { 4160 DMLabel label; 4161 PetscInt points[1024], n, pStart, pEnd, Nl = 1; 4162 char fulloption[PETSC_MAX_PATH_LEN]; 4163 char name[PETSC_MAX_PATH_LEN]; 4164 size_t len; 4165 4166 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4167 PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN)); 4168 PetscCall(PetscStrlen(name, &len)); 4169 if (name[len - 1] == '0') Nl = 10; 4170 for (PetscInt l = 0; l < Nl; ++l) { 4171 if (l > 0) name[len - 1] = '0' + l; 4172 fulloption[0] = 0; 4173 PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32)); 4174 PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32)); 4175 n = 1024; 4176 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg)); 4177 if (!flg) break; 4178 PetscCall(DMCreateLabel(dm, name)); 4179 PetscCall(DMGetLabel(dm, name, &label)); 4180 if (pStart >= pEnd) n = 0; 4181 for (PetscInt p = 0; p < n; ++p) { 4182 const PetscInt point = points[p]; 4183 PetscInt *closure = NULL; 4184 PetscInt clSize, pdepth; 4185 4186 PetscCall(DMPlexGetPointDepth(dm, point, &pdepth)); 4187 PetscCall(DMLabelSetValue(label, point, pdepth)); 4188 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4189 for (PetscInt cl = 0; cl < clSize * 2; cl += 2) { 4190 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth)); 4191 PetscCall(DMLabelSetValue(label, closure[cl], pdepth)); 4192 } 4193 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4194 } 4195 PetscCall(DMPlexOrientLabel(dm, label)); 4196 PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL)); 4197 } 4198 } 4199 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 4200 PetscFunctionReturn(PETSC_SUCCESS); 4201 } 4202 4203 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4204 { 4205 DM_Plex *mesh = (DM_Plex *)dm->data; 4206 PetscBool flg, flg2; 4207 char bdLabel[PETSC_MAX_PATH_LEN]; 4208 char method[PETSC_MAX_PATH_LEN]; 4209 4210 PetscFunctionBegin; 4211 /* Handle viewing */ 4212 PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL)); 4213 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0)); 4214 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0)); 4215 PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL)); 4216 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0)); 4217 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0)); 4218 PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg)); 4219 if (flg) PetscCall(PetscLogDefaultBegin()); 4220 /* Labeling */ 4221 PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg)); 4222 if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel)); 4223 /* Point Location */ 4224 PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL)); 4225 /* Partitioning and distribution */ 4226 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL)); 4227 /* Reordering */ 4228 PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg)); 4229 if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE)); 4230 PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg)); 4231 if (flg) PetscCall(DMReorderSectionSetType(dm, method)); 4232 /* Generation and remeshing */ 4233 PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL)); 4234 /* Projection behavior */ 4235 PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0)); 4236 PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL)); 4237 /* Checking structure */ 4238 { 4239 PetscBool all = PETSC_FALSE; 4240 4241 PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL)); 4242 if (all) { 4243 PetscCall(DMPlexCheck(dm)); 4244 } else { 4245 PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2)); 4246 if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm)); 4247 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)); 4248 if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0)); 4249 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)); 4250 if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0)); 4251 PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2)); 4252 if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm)); 4253 PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2)); 4254 if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 4255 PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2)); 4256 if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm)); 4257 } 4258 PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2)); 4259 if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE)); 4260 } 4261 { 4262 PetscReal scale = 1.0; 4263 4264 PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg)); 4265 if (flg) { 4266 Vec coordinates, coordinatesLocal; 4267 4268 PetscCall(DMGetCoordinates(dm, &coordinates)); 4269 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 4270 PetscCall(VecScale(coordinates, scale)); 4271 PetscCall(VecScale(coordinatesLocal, scale)); 4272 } 4273 } 4274 PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner)); 4275 PetscFunctionReturn(PETSC_SUCCESS); 4276 } 4277 4278 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap) 4279 { 4280 PetscInt numOvLabels = 16, numOvExLabels = 16; 4281 char *ovLabelNames[16], *ovExLabelNames[16]; 4282 PetscInt numOvValues = 16, numOvExValues = 16, l; 4283 PetscBool flg; 4284 4285 PetscFunctionBegin; 4286 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0)); 4287 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg)); 4288 if (!flg) numOvLabels = 0; 4289 if (numOvLabels) { 4290 ((DM_Plex *)dm->data)->numOvLabels = numOvLabels; 4291 for (l = 0; l < numOvLabels; ++l) { 4292 PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l])); 4293 PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]); 4294 PetscCall(PetscFree(ovLabelNames[l])); 4295 } 4296 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg)); 4297 if (!flg) numOvValues = 0; 4298 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); 4299 4300 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg)); 4301 if (!flg) numOvExLabels = 0; 4302 ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels; 4303 for (l = 0; l < numOvExLabels; ++l) { 4304 PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l])); 4305 PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]); 4306 PetscCall(PetscFree(ovExLabelNames[l])); 4307 } 4308 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg)); 4309 if (!flg) numOvExValues = 0; 4310 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); 4311 } 4312 PetscFunctionReturn(PETSC_SUCCESS); 4313 } 4314 4315 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4316 { 4317 PetscFunctionList ordlist; 4318 char oname[256]; 4319 char sublabelname[PETSC_MAX_PATH_LEN] = ""; 4320 DMReorderDefaultFlag reorder; 4321 PetscReal volume = -1.0; 4322 PetscInt prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim; 4323 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; 4324 4325 PetscFunctionBegin; 4326 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options"); 4327 if (dm->cloneOpts) goto non_refine; 4328 /* Handle automatic creation */ 4329 PetscCall(DMGetDimension(dm, &dim)); 4330 if (dim < 0) { 4331 PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm)); 4332 created = PETSC_TRUE; 4333 } 4334 PetscCall(DMGetDimension(dm, &dim)); 4335 /* Handle interpolation before distribution */ 4336 PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg)); 4337 if (flg) { 4338 DMPlexInterpolatedFlag interpolated; 4339 4340 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 4341 if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) { 4342 DM udm; 4343 4344 PetscCall(DMPlexUninterpolate(dm, &udm)); 4345 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4346 } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) { 4347 DM idm; 4348 4349 PetscCall(DMPlexInterpolate(dm, &idm)); 4350 PetscCall(DMPlexReplace_Internal(dm, &idm)); 4351 } 4352 } 4353 // Handle submesh selection before distribution 4354 PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg)); 4355 if (flg) { 4356 DM subdm; 4357 DMLabel label; 4358 IS valueIS, pointIS; 4359 const PetscInt *values, *points; 4360 PetscBool markedFaces = PETSC_FALSE; 4361 PetscInt Nv, value, Np; 4362 4363 PetscCall(DMGetLabel(dm, sublabelname, &label)); 4364 PetscCall(DMLabelGetNumValues(label, &Nv)); 4365 PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv); 4366 PetscCall(DMLabelGetValueIS(label, &valueIS)); 4367 PetscCall(ISGetIndices(valueIS, &values)); 4368 value = values[0]; 4369 PetscCall(ISRestoreIndices(valueIS, &values)); 4370 PetscCall(ISDestroy(&valueIS)); 4371 PetscCall(DMLabelGetStratumSize(label, value, &Np)); 4372 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 4373 PetscCall(ISGetIndices(pointIS, &points)); 4374 for (PetscInt p = 0; p < Np; ++p) { 4375 PetscInt pdepth; 4376 4377 PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth)); 4378 if (pdepth) { 4379 markedFaces = PETSC_TRUE; 4380 break; 4381 } 4382 } 4383 PetscCall(ISRestoreIndices(pointIS, &points)); 4384 PetscCall(ISDestroy(&pointIS)); 4385 PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm)); 4386 PetscCall(DMPlexReplace_Internal(dm, &subdm)); 4387 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4388 } 4389 /* Handle DMPlex refinement before distribution */ 4390 PetscCall(PetscOptionsBool("-dm_refine_ignore_model", "Flag to ignore the geometry model when refining", "DMCreate", ignoreModel, &ignoreModel, &flg)); 4391 if (flg) ((DM_Plex *)dm->data)->ignoreModel = ignoreModel; 4392 PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig)); 4393 PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0)); 4394 PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4395 PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg)); 4396 if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform)); 4397 PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg)); 4398 if (flg) { 4399 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE)); 4400 PetscCall(DMPlexSetRefinementLimit(dm, volume)); 4401 prerefine = PetscMax(prerefine, 1); 4402 } 4403 if (prerefine) PetscCall(DMLocalizeCoordinates(dm)); 4404 for (r = 0; r < prerefine; ++r) { 4405 DM rdm; 4406 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4407 4408 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4409 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4410 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4411 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4412 if (coordFunc && remap) { 4413 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4414 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4415 } 4416 } 4417 PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig)); 4418 /* Handle DMPlex extrusion before distribution */ 4419 PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0)); 4420 if (extLayers) { 4421 DM edm; 4422 4423 PetscCall(DMExtrude(dm, extLayers, &edm)); 4424 PetscCall(DMPlexReplace_Internal(dm, &edm)); 4425 ((DM_Plex *)dm->data)->coordFunc = NULL; 4426 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4427 extLayers = 0; 4428 PetscCall(DMGetDimension(dm, &dim)); 4429 } 4430 /* Handle DMPlex reordering before distribution */ 4431 PetscCall(DMPlexReorderGetDefault(dm, &reorder)); 4432 PetscCall(MatGetOrderingList(&ordlist)); 4433 PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname))); 4434 PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg)); 4435 if (reorder == DM_REORDER_DEFAULT_TRUE || flg) { 4436 DM pdm; 4437 IS perm; 4438 4439 PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm)); 4440 PetscCall(DMPlexPermute(dm, perm, &pdm)); 4441 PetscCall(ISDestroy(&perm)); 4442 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4443 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4444 } 4445 /* Handle DMPlex distribution */ 4446 PetscCall(DMPlexDistributeGetDefault(dm, &distribute)); 4447 PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL)); 4448 PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL)); 4449 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 4450 if (distribute) { 4451 DM pdm = NULL; 4452 PetscPartitioner part; 4453 PetscSF sfMigration; 4454 4455 PetscCall(DMPlexGetPartitioner(dm, &part)); 4456 PetscCall(PetscPartitionerSetFromOptions(part)); 4457 PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm)); 4458 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4459 if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration)); 4460 PetscCall(PetscSFDestroy(&sfMigration)); 4461 } 4462 /* Must check CEED options before creating function space for coordinates */ 4463 { 4464 PetscBool useCeed = PETSC_FALSE, flg; 4465 4466 PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg)); 4467 if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed)); 4468 } 4469 /* Create coordinate space */ 4470 if (created) { 4471 DM_Plex *mesh = (DM_Plex *)dm->data; 4472 PetscInt degree = 1, deg; 4473 PetscInt height = 0; 4474 DM cdm; 4475 PetscBool flg, localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE; 4476 4477 PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg)); 4478 PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, °ree, NULL)); 4479 PetscCall(DMGetCoordinateDegree_Internal(dm, °)); 4480 if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, mesh->coordFunc)); 4481 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4482 if (flg && !coordSpace) { 4483 PetscDS cds; 4484 PetscObject obj; 4485 PetscClassId id; 4486 4487 PetscCall(DMGetDS(cdm, &cds)); 4488 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4489 PetscCall(PetscObjectGetClassId(obj, &id)); 4490 if (id == PETSCFE_CLASSID) { 4491 PetscContainer dummy; 4492 4493 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy)); 4494 PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates")); 4495 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy)); 4496 PetscCall(PetscContainerDestroy(&dummy)); 4497 PetscCall(DMClearDS(cdm)); 4498 } 4499 mesh->coordFunc = NULL; 4500 } 4501 PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL)); 4502 PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg)); 4503 if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize)); 4504 PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg)); 4505 if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height)); 4506 if (localize) PetscCall(DMLocalizeCoordinates(dm)); 4507 } 4508 /* Handle DMPlex refinement */ 4509 remap = PETSC_TRUE; 4510 PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0)); 4511 PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4512 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0)); 4513 if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4514 if (refine && isHierarchy) { 4515 DM *dms, coarseDM; 4516 4517 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 4518 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 4519 PetscCall(PetscMalloc1(refine, &dms)); 4520 PetscCall(DMRefineHierarchy(dm, refine, dms)); 4521 /* Total hack since we do not pass in a pointer */ 4522 PetscCall(DMPlexSwap_Static(dm, dms[refine - 1])); 4523 if (refine == 1) { 4524 PetscCall(DMSetCoarseDM(dm, dms[0])); 4525 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4526 } else { 4527 PetscCall(DMSetCoarseDM(dm, dms[refine - 2])); 4528 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4529 PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1])); 4530 PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE)); 4531 } 4532 PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM)); 4533 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 4534 /* Free DMs */ 4535 for (r = 0; r < refine; ++r) { 4536 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4537 PetscCall(DMDestroy(&dms[r])); 4538 } 4539 PetscCall(PetscFree(dms)); 4540 } else { 4541 for (r = 0; r < refine; ++r) { 4542 DM rdm; 4543 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4544 4545 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4546 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4547 /* Total hack since we do not pass in a pointer */ 4548 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4549 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4550 if (coordFunc && remap) { 4551 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4552 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4553 } 4554 } 4555 } 4556 /* Handle DMPlex coarsening */ 4557 PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0)); 4558 PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0)); 4559 if (coarsen && isHierarchy) { 4560 DM *dms; 4561 4562 PetscCall(PetscMalloc1(coarsen, &dms)); 4563 PetscCall(DMCoarsenHierarchy(dm, coarsen, dms)); 4564 /* Free DMs */ 4565 for (r = 0; r < coarsen; ++r) { 4566 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4567 PetscCall(DMDestroy(&dms[r])); 4568 } 4569 PetscCall(PetscFree(dms)); 4570 } else { 4571 for (r = 0; r < coarsen; ++r) { 4572 DM cdm; 4573 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4574 4575 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4576 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm)); 4577 /* Total hack since we do not pass in a pointer */ 4578 PetscCall(DMPlexReplace_Internal(dm, &cdm)); 4579 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4580 if (coordFunc) { 4581 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4582 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4583 } 4584 } 4585 } 4586 // Handle coordinate remapping 4587 remap = PETSC_FALSE; 4588 PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL)); 4589 if (remap) { 4590 DMPlexCoordMap map = DM_COORD_MAP_NONE; 4591 PetscPointFunc mapFunc = NULL; 4592 PetscScalar params[16]; 4593 PetscInt Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim; 4594 MPI_Comm comm; 4595 4596 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4597 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4598 PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg)); 4599 if (!flg) Np = 0; 4600 // TODO Allow user to pass a map function by name 4601 PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg)); 4602 if (flg) { 4603 switch (map) { 4604 case DM_COORD_MAP_NONE: 4605 mapFunc = coordMap_identity; 4606 break; 4607 case DM_COORD_MAP_SHEAR: 4608 mapFunc = coordMap_shear; 4609 if (!Np) { 4610 Np = cdim + 1; 4611 params[0] = 0; 4612 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 4613 } 4614 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); 4615 break; 4616 case DM_COORD_MAP_FLARE: 4617 mapFunc = coordMap_flare; 4618 if (!Np) { 4619 Np = cdim + 1; 4620 params[0] = 0; 4621 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 4622 } 4623 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); 4624 break; 4625 case DM_COORD_MAP_ANNULUS: 4626 mapFunc = coordMap_annulus; 4627 if (!Np) { 4628 Np = 2; 4629 params[0] = 1.; 4630 params[1] = 2.; 4631 } 4632 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 4633 break; 4634 case DM_COORD_MAP_SHELL: 4635 mapFunc = coordMap_shell; 4636 if (!Np) { 4637 Np = 2; 4638 params[0] = 1.; 4639 params[1] = 2.; 4640 } 4641 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 4642 break; 4643 default: 4644 mapFunc = coordMap_identity; 4645 } 4646 } 4647 if (Np) { 4648 DM cdm; 4649 PetscDS cds; 4650 4651 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4652 PetscCall(DMGetDS(cdm, &cds)); 4653 PetscCall(PetscDSSetConstants(cds, Np, params)); 4654 } 4655 PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc)); 4656 } 4657 /* Handle ghost cells */ 4658 PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL)); 4659 if (ghostCells) { 4660 DM gdm; 4661 char lname[PETSC_MAX_PATH_LEN]; 4662 4663 lname[0] = '\0'; 4664 PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg)); 4665 PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm)); 4666 PetscCall(DMPlexReplace_Internal(dm, &gdm)); 4667 } 4668 /* Handle 1D order */ 4669 if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) { 4670 DM cdm, rdm; 4671 PetscDS cds; 4672 PetscObject obj; 4673 PetscClassId id = PETSC_OBJECT_CLASSID; 4674 IS perm; 4675 PetscInt Nf; 4676 PetscBool distributed; 4677 4678 PetscCall(DMPlexIsDistributed(dm, &distributed)); 4679 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4680 PetscCall(DMGetDS(cdm, &cds)); 4681 PetscCall(PetscDSGetNumFields(cds, &Nf)); 4682 if (Nf) { 4683 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4684 PetscCall(PetscObjectGetClassId(obj, &id)); 4685 } 4686 if (!distributed && id != PETSCFE_CLASSID) { 4687 PetscCall(DMPlexGetOrdering1D(dm, &perm)); 4688 PetscCall(DMPlexPermute(dm, perm, &rdm)); 4689 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4690 PetscCall(ISDestroy(&perm)); 4691 } 4692 } 4693 /* Handle */ 4694 non_refine: 4695 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4696 PetscOptionsHeadEnd(); 4697 PetscFunctionReturn(PETSC_SUCCESS); 4698 } 4699 4700 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec) 4701 { 4702 PetscFunctionBegin; 4703 PetscCall(DMCreateGlobalVector_Section_Private(dm, vec)); 4704 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 4705 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex)); 4706 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native)); 4707 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex)); 4708 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native)); 4709 PetscFunctionReturn(PETSC_SUCCESS); 4710 } 4711 4712 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec) 4713 { 4714 PetscFunctionBegin; 4715 PetscCall(DMCreateLocalVector_Section_Private(dm, vec)); 4716 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local)); 4717 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local)); 4718 PetscFunctionReturn(PETSC_SUCCESS); 4719 } 4720 4721 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 4722 { 4723 PetscInt depth, d; 4724 4725 PetscFunctionBegin; 4726 PetscCall(DMPlexGetDepth(dm, &depth)); 4727 if (depth == 1) { 4728 PetscCall(DMGetDimension(dm, &d)); 4729 if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4730 else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd)); 4731 else { 4732 *pStart = 0; 4733 *pEnd = 0; 4734 } 4735 } else { 4736 PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4737 } 4738 PetscFunctionReturn(PETSC_SUCCESS); 4739 } 4740 4741 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 4742 { 4743 PetscSF sf; 4744 PetscInt niranks, njranks, n; 4745 const PetscMPIInt *iranks, *jranks; 4746 DM_Plex *data = (DM_Plex *)dm->data; 4747 4748 PetscFunctionBegin; 4749 PetscCall(DMGetPointSF(dm, &sf)); 4750 if (!data->neighbors) { 4751 PetscCall(PetscSFSetUp(sf)); 4752 PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL)); 4753 PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL)); 4754 PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors)); 4755 PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks)); 4756 PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks)); 4757 n = njranks + niranks; 4758 PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1)); 4759 /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */ 4760 PetscCall(PetscMPIIntCast(n, data->neighbors)); 4761 } 4762 if (nranks) *nranks = data->neighbors[0]; 4763 if (ranks) { 4764 if (data->neighbors[0]) *ranks = data->neighbors + 1; 4765 else *ranks = NULL; 4766 } 4767 PetscFunctionReturn(PETSC_SUCCESS); 4768 } 4769 4770 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec); 4771 4772 static PetscErrorCode DMInitialize_Plex(DM dm) 4773 { 4774 PetscFunctionBegin; 4775 dm->ops->view = DMView_Plex; 4776 dm->ops->load = DMLoad_Plex; 4777 dm->ops->setfromoptions = DMSetFromOptions_Plex; 4778 dm->ops->clone = DMClone_Plex; 4779 dm->ops->setup = DMSetUp_Plex; 4780 dm->ops->createlocalsection = DMCreateLocalSection_Plex; 4781 dm->ops->createsectionpermutation = DMCreateSectionPermutation_Plex; 4782 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_Plex; 4783 dm->ops->createglobalvector = DMCreateGlobalVector_Plex; 4784 dm->ops->createlocalvector = DMCreateLocalVector_Plex; 4785 dm->ops->getlocaltoglobalmapping = NULL; 4786 dm->ops->createfieldis = NULL; 4787 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Plex; 4788 dm->ops->createcoordinatefield = DMCreateCoordinateField_Plex; 4789 dm->ops->getcoloring = NULL; 4790 dm->ops->creatematrix = DMCreateMatrix_Plex; 4791 dm->ops->createinterpolation = DMCreateInterpolation_Plex; 4792 dm->ops->createmassmatrix = DMCreateMassMatrix_Plex; 4793 dm->ops->createmassmatrixlumped = DMCreateMassMatrixLumped_Plex; 4794 dm->ops->createinjection = DMCreateInjection_Plex; 4795 dm->ops->refine = DMRefine_Plex; 4796 dm->ops->coarsen = DMCoarsen_Plex; 4797 dm->ops->refinehierarchy = DMRefineHierarchy_Plex; 4798 dm->ops->coarsenhierarchy = DMCoarsenHierarchy_Plex; 4799 dm->ops->extrude = DMExtrude_Plex; 4800 dm->ops->globaltolocalbegin = NULL; 4801 dm->ops->globaltolocalend = NULL; 4802 dm->ops->localtoglobalbegin = NULL; 4803 dm->ops->localtoglobalend = NULL; 4804 dm->ops->destroy = DMDestroy_Plex; 4805 dm->ops->createsubdm = DMCreateSubDM_Plex; 4806 dm->ops->createsuperdm = DMCreateSuperDM_Plex; 4807 dm->ops->getdimpoints = DMGetDimPoints_Plex; 4808 dm->ops->locatepoints = DMLocatePoints_Plex; 4809 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_Plex; 4810 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex; 4811 dm->ops->projectfieldlocal = DMProjectFieldLocal_Plex; 4812 dm->ops->projectfieldlabellocal = DMProjectFieldLabelLocal_Plex; 4813 dm->ops->projectbdfieldlabellocal = DMProjectBdFieldLabelLocal_Plex; 4814 dm->ops->computel2diff = DMComputeL2Diff_Plex; 4815 dm->ops->computel2gradientdiff = DMComputeL2GradientDiff_Plex; 4816 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_Plex; 4817 dm->ops->getneighbors = DMGetNeighbors_Plex; 4818 dm->ops->getlocalboundingbox = DMGetLocalBoundingBox_Coordinates; 4819 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex; 4820 dm->ops->createddscatters = DMCreateDomainDecompositionScatters_Plex; 4821 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex)); 4822 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex)); 4823 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex)); 4824 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex)); 4825 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex)); 4826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex)); 4827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex)); 4828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex)); 4829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex)); 4830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex)); 4831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex)); 4832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex)); 4833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex)); 4834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 4835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex)); 4836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex)); 4837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex)); 4838 PetscFunctionReturn(PETSC_SUCCESS); 4839 } 4840 4841 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm) 4842 { 4843 DM_Plex *mesh = (DM_Plex *)dm->data; 4844 const PetscSF *face_sfs; 4845 PetscInt num_face_sfs; 4846 4847 PetscFunctionBegin; 4848 mesh->refct++; 4849 (*newdm)->data = mesh; 4850 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs)); 4851 PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs)); 4852 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX)); 4853 PetscCall(DMInitialize_Plex(*newdm)); 4854 PetscFunctionReturn(PETSC_SUCCESS); 4855 } 4856 4857 /*MC 4858 DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram. 4859 In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is 4860 specified by a PetscSection object. Ownership in the global representation is determined by 4861 ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object. 4862 4863 Options Database Keys: 4864 + -dm_refine_pre - Refine mesh before distribution 4865 + -dm_refine_uniform_pre - Choose uniform or generator-based refinement 4866 + -dm_refine_volume_limit_pre - Cell volume limit after pre-refinement using generator 4867 . -dm_distribute - Distribute mesh across processes 4868 . -dm_distribute_overlap - Number of cells to overlap for distribution 4869 . -dm_refine - Refine mesh after distribution 4870 . -dm_localize <bool> - Whether to localize coordinates for periodic meshes 4871 . -dm_sparse_localize <bool> - Whether to only localize cells on the periodic boundary 4872 . -dm_plex_hash_location - Use grid hashing for point location 4873 . -dm_plex_hash_box_faces <n,m,p> - The number of divisions in each direction of the grid hash 4874 . -dm_plex_partition_balance - Attempt to evenly divide points on partition boundary between processes 4875 . -dm_plex_remesh_bd - Allow changes to the boundary on remeshing 4876 . -dm_plex_max_projection_height - Maximum mesh point height used to project locally 4877 . -dm_plex_regular_refinement - Use special nested projection algorithm for regular refinement 4878 . -dm_plex_reorder_section - Use specialized blocking if available 4879 . -dm_plex_check_all - Perform all checks below 4880 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric 4881 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices 4882 . -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 4883 . -dm_plex_check_geometry - Check that cells have positive volume 4884 . -dm_view :mesh.tex:ascii_latex - View the mesh in LaTeX/TikZ 4885 . -dm_plex_view_scale <num> - Scale the TikZ 4886 . -dm_plex_print_fem <num> - View FEM assembly information, such as element vectors and matrices 4887 - -dm_plex_print_fvm <num> - View FVM assembly information, such as flux updates 4888 4889 Level: intermediate 4890 4891 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection` 4892 M*/ 4893 4894 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm) 4895 { 4896 DM_Plex *mesh; 4897 PetscInt unit; 4898 4899 PetscFunctionBegin; 4900 PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite)); 4901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4902 PetscCall(PetscNew(&mesh)); 4903 dm->reorderSection = DM_REORDER_DEFAULT_NOTSET; 4904 dm->data = mesh; 4905 4906 mesh->refct = 1; 4907 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection)); 4908 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection)); 4909 mesh->refinementUniform = PETSC_TRUE; 4910 mesh->refinementLimit = -1.0; 4911 mesh->distDefault = PETSC_TRUE; 4912 mesh->reorderDefault = DM_REORDER_DEFAULT_NOTSET; 4913 mesh->distributionName = NULL; 4914 mesh->interpolated = DMPLEX_INTERPOLATED_INVALID; 4915 mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID; 4916 4917 PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner)); 4918 mesh->remeshBd = PETSC_FALSE; 4919 4920 for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0; 4921 4922 mesh->depthState = -1; 4923 mesh->celltypeState = -1; 4924 mesh->printTol = 1.0e-10; 4925 4926 PetscCall(DMInitialize_Plex(dm)); 4927 PetscFunctionReturn(PETSC_SUCCESS); 4928 } 4929 4930 /*@ 4931 DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram. 4932 4933 Collective 4934 4935 Input Parameter: 4936 . comm - The communicator for the `DMPLEX` object 4937 4938 Output Parameter: 4939 . mesh - The `DMPLEX` object 4940 4941 Level: beginner 4942 4943 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()` 4944 @*/ 4945 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh) 4946 { 4947 PetscFunctionBegin; 4948 PetscAssertPointer(mesh, 2); 4949 PetscCall(DMCreate(comm, mesh)); 4950 PetscCall(DMSetType(*mesh, DMPLEX)); 4951 PetscFunctionReturn(PETSC_SUCCESS); 4952 } 4953 4954 /*@C 4955 DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 4956 4957 Collective; No Fortran Support 4958 4959 Input Parameters: 4960 + dm - The `DM` 4961 . numCells - The number of cells owned by this process 4962 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 4963 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 4964 . numCorners - The number of vertices for each cell 4965 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 4966 4967 Output Parameters: 4968 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 4969 - verticesAdjSaved - (Optional) vertex adjacency array 4970 4971 Level: advanced 4972 4973 Notes: 4974 Two triangles sharing a face 4975 .vb 4976 4977 2 4978 / | \ 4979 / | \ 4980 / | \ 4981 0 0 | 1 3 4982 \ | / 4983 \ | / 4984 \ | / 4985 1 4986 .ve 4987 would have input 4988 .vb 4989 numCells = 2, numVertices = 4 4990 cells = [0 1 2 1 3 2] 4991 .ve 4992 which would result in the `DMPLEX` 4993 .vb 4994 4995 4 4996 / | \ 4997 / | \ 4998 / | \ 4999 2 0 | 1 5 5000 \ | / 5001 \ | / 5002 \ | / 5003 3 5004 .ve 5005 5006 Vertices are implicitly numbered consecutively 0,...,NVertices. 5007 Each rank owns a chunk of numVertices consecutive vertices. 5008 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 5009 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 5010 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 5011 5012 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 5013 5014 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 5015 `PetscSF` 5016 @*/ 5017 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved) 5018 { 5019 PetscSF sfPoint; 5020 PetscLayout layout; 5021 PetscInt numVerticesAdj, *verticesAdj, *cones, c, p; 5022 5023 PetscFunctionBegin; 5024 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 5025 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5026 /* Get/check global number of vertices */ 5027 { 5028 PetscInt NVerticesInCells, i; 5029 const PetscInt len = numCells * numCorners; 5030 5031 /* NVerticesInCells = max(cells) + 1 */ 5032 NVerticesInCells = PETSC_MIN_INT; 5033 for (i = 0; i < len; i++) 5034 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5035 ++NVerticesInCells; 5036 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 5037 5038 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 5039 else 5040 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); 5041 } 5042 /* Count locally unique vertices */ 5043 { 5044 PetscHSetI vhash; 5045 PetscInt off = 0; 5046 5047 PetscCall(PetscHSetICreate(&vhash)); 5048 for (c = 0; c < numCells; ++c) { 5049 for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p])); 5050 } 5051 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 5052 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 5053 else verticesAdj = *verticesAdjSaved; 5054 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 5055 PetscCall(PetscHSetIDestroy(&vhash)); 5056 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 5057 } 5058 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 5059 /* Create cones */ 5060 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 5061 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5062 PetscCall(DMSetUp(dm)); 5063 PetscCall(DMPlexGetCones(dm, &cones)); 5064 for (c = 0; c < numCells; ++c) { 5065 for (p = 0; p < numCorners; ++p) { 5066 const PetscInt gv = cells[c * numCorners + p]; 5067 PetscInt lv; 5068 5069 /* Positions within verticesAdj form 0-based local vertex numbering; 5070 we need to shift it by numCells to get correct DAG points (cells go first) */ 5071 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 5072 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 5073 cones[c * numCorners + p] = lv + numCells; 5074 } 5075 } 5076 /* Build point sf */ 5077 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 5078 PetscCall(PetscLayoutSetSize(layout, NVertices)); 5079 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 5080 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 5081 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 5082 PetscCall(PetscLayoutDestroy(&layout)); 5083 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 5084 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 5085 if (dm->sf) { 5086 const char *prefix; 5087 5088 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 5089 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 5090 } 5091 PetscCall(DMSetPointSF(dm, sfPoint)); 5092 PetscCall(PetscSFDestroy(&sfPoint)); 5093 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 5094 /* Fill in the rest of the topology structure */ 5095 PetscCall(DMPlexSymmetrize(dm)); 5096 PetscCall(DMPlexStratify(dm)); 5097 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5098 PetscFunctionReturn(PETSC_SUCCESS); 5099 } 5100 5101 /*@ 5102 DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 5103 5104 Collective; No Fortran Support 5105 5106 Input Parameters: 5107 + dm - The `DM` 5108 . spaceDim - The spatial dimension used for coordinates 5109 . sfVert - `PetscSF` describing complete vertex ownership 5110 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5111 5112 Level: advanced 5113 5114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()` 5115 @*/ 5116 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[]) 5117 { 5118 PetscSection coordSection; 5119 Vec coordinates; 5120 PetscScalar *coords; 5121 PetscInt numVertices, numVerticesAdj, coordSize, v, vStart, vEnd; 5122 5123 PetscFunctionBegin; 5124 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5125 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 5126 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 5127 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 5128 PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL)); 5129 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); 5130 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5131 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5132 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 5133 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 5134 for (v = vStart; v < vEnd; ++v) { 5135 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 5136 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 5137 } 5138 PetscCall(PetscSectionSetUp(coordSection)); 5139 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5140 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates)); 5141 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 5142 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5143 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5144 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5145 PetscCall(VecGetArray(coordinates, &coords)); 5146 { 5147 MPI_Datatype coordtype; 5148 5149 /* Need a temp buffer for coords if we have complex/single */ 5150 PetscCallMPI(MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype)); 5151 PetscCallMPI(MPI_Type_commit(&coordtype)); 5152 #if defined(PETSC_USE_COMPLEX) 5153 { 5154 PetscScalar *svertexCoords; 5155 PetscInt i; 5156 PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords)); 5157 for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i]; 5158 PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 5159 PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 5160 PetscCall(PetscFree(svertexCoords)); 5161 } 5162 #else 5163 PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 5164 PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 5165 #endif 5166 PetscCallMPI(MPI_Type_free(&coordtype)); 5167 } 5168 PetscCall(VecRestoreArray(coordinates, &coords)); 5169 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5170 PetscCall(VecDestroy(&coordinates)); 5171 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5172 PetscFunctionReturn(PETSC_SUCCESS); 5173 } 5174 5175 /*@ 5176 DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) 5177 5178 Collective 5179 5180 Input Parameters: 5181 + comm - The communicator 5182 . dim - The topological dimension of the mesh 5183 . numCells - The number of cells owned by this process 5184 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 5185 . NVertices - The global number of vertices, or `PETSC_DECIDE` 5186 . numCorners - The number of vertices for each cell 5187 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5188 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5189 . spaceDim - The spatial dimension used for coordinates 5190 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5191 5192 Output Parameters: 5193 + dm - The `DM` 5194 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5195 - verticesAdj - (Optional) vertex adjacency array 5196 5197 Level: intermediate 5198 5199 Notes: 5200 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 5201 `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 5202 5203 See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters. 5204 5205 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 5206 5207 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5208 @*/ 5209 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) 5210 { 5211 PetscSF sfVert; 5212 5213 PetscFunctionBegin; 5214 PetscCall(DMCreate(comm, dm)); 5215 PetscCall(DMSetType(*dm, DMPLEX)); 5216 PetscValidLogicalCollectiveInt(*dm, dim, 2); 5217 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 5218 PetscCall(DMSetDimension(*dm, dim)); 5219 PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj)); 5220 if (interpolate) { 5221 DM idm; 5222 5223 PetscCall(DMPlexInterpolate(*dm, &idm)); 5224 PetscCall(DMDestroy(dm)); 5225 *dm = idm; 5226 } 5227 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 5228 if (vertexSF) *vertexSF = sfVert; 5229 else PetscCall(PetscSFDestroy(&sfVert)); 5230 PetscFunctionReturn(PETSC_SUCCESS); 5231 } 5232 5233 /*@ 5234 DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 5235 5236 Collective; No Fortran Support 5237 5238 Input Parameters: 5239 + dm - The `DM` 5240 . numCells - The number of cells owned by this process 5241 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE` 5242 . numCorners - The number of vertices for each cell 5243 - cells - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell 5244 5245 Level: advanced 5246 5247 Notes: 5248 Two triangles sharing a face 5249 .vb 5250 5251 2 5252 / | \ 5253 / | \ 5254 / | \ 5255 0 0 | 1 3 5256 \ | / 5257 \ | / 5258 \ | / 5259 1 5260 .ve 5261 would have input 5262 .vb 5263 numCells = 2, numVertices = 4 5264 cells = [0 1 2 1 3 2] 5265 .ve 5266 which would result in the `DMPLEX` 5267 .vb 5268 5269 4 5270 / | \ 5271 / | \ 5272 / | \ 5273 2 0 | 1 5 5274 \ | / 5275 \ | / 5276 \ | / 5277 3 5278 .ve 5279 5280 If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1. 5281 5282 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()` 5283 @*/ 5284 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[]) 5285 { 5286 PetscInt *cones, c, p, dim; 5287 5288 PetscFunctionBegin; 5289 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5290 PetscCall(DMGetDimension(dm, &dim)); 5291 /* Get/check global number of vertices */ 5292 { 5293 PetscInt NVerticesInCells, i; 5294 const PetscInt len = numCells * numCorners; 5295 5296 /* NVerticesInCells = max(cells) + 1 */ 5297 NVerticesInCells = PETSC_MIN_INT; 5298 for (i = 0; i < len; i++) 5299 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5300 ++NVerticesInCells; 5301 5302 if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells; 5303 else 5304 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); 5305 } 5306 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 5307 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5308 PetscCall(DMSetUp(dm)); 5309 PetscCall(DMPlexGetCones(dm, &cones)); 5310 for (c = 0; c < numCells; ++c) { 5311 for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells; 5312 } 5313 PetscCall(DMPlexSymmetrize(dm)); 5314 PetscCall(DMPlexStratify(dm)); 5315 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5316 PetscFunctionReturn(PETSC_SUCCESS); 5317 } 5318 5319 /*@ 5320 DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 5321 5322 Collective 5323 5324 Input Parameters: 5325 + dm - The `DM` 5326 . spaceDim - The spatial dimension used for coordinates 5327 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5328 5329 Level: advanced 5330 5331 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()` 5332 @*/ 5333 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[]) 5334 { 5335 PetscSection coordSection; 5336 Vec coordinates; 5337 DM cdm; 5338 PetscScalar *coords; 5339 PetscInt v, vStart, vEnd, d; 5340 5341 PetscFunctionBegin; 5342 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5343 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 5344 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 5345 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 5346 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5347 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5348 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 5349 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 5350 for (v = vStart; v < vEnd; ++v) { 5351 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 5352 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 5353 } 5354 PetscCall(PetscSectionSetUp(coordSection)); 5355 5356 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5357 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 5358 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 5359 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5360 PetscCall(VecGetArrayWrite(coordinates, &coords)); 5361 for (v = 0; v < vEnd - vStart; ++v) { 5362 for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d]; 5363 } 5364 PetscCall(VecRestoreArrayWrite(coordinates, &coords)); 5365 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5366 PetscCall(VecDestroy(&coordinates)); 5367 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5368 PetscFunctionReturn(PETSC_SUCCESS); 5369 } 5370 5371 /*@ 5372 DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input 5373 5374 Collective 5375 5376 Input Parameters: 5377 + comm - The communicator 5378 . dim - The topological dimension of the mesh 5379 . numCells - The number of cells, only on process 0 5380 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0 5381 . numCorners - The number of vertices for each cell, only on process 0 5382 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5383 . cells - An array of numCells*numCorners numbers, the vertices for each cell, only on process 0 5384 . spaceDim - The spatial dimension used for coordinates 5385 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex, only on process 0 5386 5387 Output Parameter: 5388 . dm - The `DM`, which only has points on process 0 5389 5390 Level: intermediate 5391 5392 Notes: 5393 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`, 5394 `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()` 5395 5396 See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters. 5397 See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters. 5398 See `DMPlexCreateFromCellListParallelPetsc()` for parallel input 5399 5400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5401 @*/ 5402 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) 5403 { 5404 PetscMPIInt rank; 5405 5406 PetscFunctionBegin; 5407 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."); 5408 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5409 PetscCall(DMCreate(comm, dm)); 5410 PetscCall(DMSetType(*dm, DMPLEX)); 5411 PetscCall(DMSetDimension(*dm, dim)); 5412 if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells)); 5413 else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL)); 5414 if (interpolate) { 5415 DM idm; 5416 5417 PetscCall(DMPlexInterpolate(*dm, &idm)); 5418 PetscCall(DMDestroy(dm)); 5419 *dm = idm; 5420 } 5421 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords)); 5422 else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL)); 5423 PetscFunctionReturn(PETSC_SUCCESS); 5424 } 5425 5426 /*@ 5427 DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM` 5428 5429 Input Parameters: 5430 + dm - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()` 5431 . depth - The depth of the DAG 5432 . numPoints - Array of size depth + 1 containing the number of points at each `depth` 5433 . coneSize - The cone size of each point 5434 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point 5435 . coneOrientations - The orientation of each cone point 5436 - vertexCoords - An array of `numPoints`[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via `DMSetCoordinateDim()` 5437 5438 Output Parameter: 5439 . dm - The `DM` 5440 5441 Level: advanced 5442 5443 Note: 5444 Two triangles sharing a face would have input 5445 .vb 5446 depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0] 5447 cones = [2 3 4 3 5 4], coneOrientations = [0 0 0 0 0 0] 5448 vertexCoords = [-1.0 0.0 0.0 -1.0 0.0 1.0 1.0 0.0] 5449 .ve 5450 which would result in the DMPlex 5451 .vb 5452 4 5453 / | \ 5454 / | \ 5455 / | \ 5456 2 0 | 1 5 5457 \ | / 5458 \ | / 5459 \ | / 5460 3 5461 .ve 5462 Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()` 5463 5464 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 5465 @*/ 5466 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[]) 5467 { 5468 Vec coordinates; 5469 PetscSection coordSection; 5470 PetscScalar *coords; 5471 PetscInt coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off; 5472 5473 PetscFunctionBegin; 5474 PetscCall(DMGetDimension(dm, &dim)); 5475 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 5476 PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim); 5477 for (d = 0; d <= depth; ++d) pEnd += numPoints[d]; 5478 PetscCall(DMPlexSetChart(dm, pStart, pEnd)); 5479 for (p = pStart; p < pEnd; ++p) { 5480 PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart])); 5481 if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart; 5482 } 5483 PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]); 5484 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 5485 for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) { 5486 PetscCall(DMPlexSetCone(dm, p, &cones[off])); 5487 PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off])); 5488 } 5489 PetscCall(DMPlexSymmetrize(dm)); 5490 PetscCall(DMPlexStratify(dm)); 5491 /* Build coordinates */ 5492 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5493 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5494 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed)); 5495 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0])); 5496 for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) { 5497 PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed)); 5498 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed)); 5499 } 5500 PetscCall(PetscSectionSetUp(coordSection)); 5501 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5502 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 5503 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5504 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5505 PetscCall(VecSetBlockSize(coordinates, dimEmbed)); 5506 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5507 if (vertexCoords) { 5508 PetscCall(VecGetArray(coordinates, &coords)); 5509 for (v = 0; v < numPoints[0]; ++v) { 5510 PetscInt off; 5511 5512 PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off)); 5513 for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d]; 5514 } 5515 } 5516 PetscCall(VecRestoreArray(coordinates, &coords)); 5517 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5518 PetscCall(VecDestroy(&coordinates)); 5519 PetscFunctionReturn(PETSC_SUCCESS); 5520 } 5521 5522 /* 5523 DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file. 5524 5525 Collective 5526 5527 + comm - The MPI communicator 5528 . filename - Name of the .dat file 5529 - interpolate - Create faces and edges in the mesh 5530 5531 Output Parameter: 5532 . dm - The `DM` object representing the mesh 5533 5534 Level: beginner 5535 5536 Note: 5537 The format is the simplest possible: 5538 .vb 5539 dim Ne Nv Nc Nl 5540 v_1 v_2 ... v_Nc 5541 ... 5542 x y z marker_1 ... marker_Nl 5543 .ve 5544 5545 Developer Note: 5546 Should use a `PetscViewer` not a filename 5547 5548 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()` 5549 */ 5550 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 5551 { 5552 DMLabel marker; 5553 PetscViewer viewer; 5554 Vec coordinates; 5555 PetscSection coordSection; 5556 PetscScalar *coords; 5557 char line[PETSC_MAX_PATH_LEN]; 5558 PetscInt cdim, coordSize, v, c, d; 5559 PetscMPIInt rank; 5560 int snum, dim, Nv, Nc, Ncn, Nl; 5561 5562 PetscFunctionBegin; 5563 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5564 PetscCall(PetscViewerCreate(comm, &viewer)); 5565 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII)); 5566 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 5567 PetscCall(PetscViewerFileSetName(viewer, filename)); 5568 if (rank == 0) { 5569 PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING)); 5570 snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl); 5571 PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5572 } else { 5573 Nc = Nv = Ncn = Nl = 0; 5574 } 5575 PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm)); 5576 cdim = (PetscInt)dim; 5577 PetscCall(DMCreate(comm, dm)); 5578 PetscCall(DMSetType(*dm, DMPLEX)); 5579 PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv)); 5580 PetscCall(DMSetDimension(*dm, (PetscInt)dim)); 5581 PetscCall(DMSetCoordinateDim(*dm, cdim)); 5582 /* Read topology */ 5583 if (rank == 0) { 5584 char format[PETSC_MAX_PATH_LEN]; 5585 PetscInt cone[8]; 5586 int vbuf[8], v; 5587 5588 for (c = 0; c < Ncn; ++c) { 5589 format[c * 3 + 0] = '%'; 5590 format[c * 3 + 1] = 'd'; 5591 format[c * 3 + 2] = ' '; 5592 } 5593 format[Ncn * 3 - 1] = '\0'; 5594 for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn)); 5595 PetscCall(DMSetUp(*dm)); 5596 for (c = 0; c < Nc; ++c) { 5597 PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING)); 5598 switch (Ncn) { 5599 case 2: 5600 snum = sscanf(line, format, &vbuf[0], &vbuf[1]); 5601 break; 5602 case 3: 5603 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]); 5604 break; 5605 case 4: 5606 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]); 5607 break; 5608 case 6: 5609 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]); 5610 break; 5611 case 8: 5612 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]); 5613 break; 5614 default: 5615 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn); 5616 } 5617 PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5618 for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc; 5619 /* Hexahedra are inverted */ 5620 if (Ncn == 8) { 5621 PetscInt tmp = cone[1]; 5622 cone[1] = cone[3]; 5623 cone[3] = tmp; 5624 } 5625 PetscCall(DMPlexSetCone(*dm, c, cone)); 5626 } 5627 } 5628 PetscCall(DMPlexSymmetrize(*dm)); 5629 PetscCall(DMPlexStratify(*dm)); 5630 /* Read coordinates */ 5631 PetscCall(DMGetCoordinateSection(*dm, &coordSection)); 5632 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5633 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 5634 PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv)); 5635 for (v = Nc; v < Nc + Nv; ++v) { 5636 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 5637 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 5638 } 5639 PetscCall(PetscSectionSetUp(coordSection)); 5640 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5641 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 5642 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5643 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5644 PetscCall(VecSetBlockSize(coordinates, cdim)); 5645 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5646 PetscCall(VecGetArray(coordinates, &coords)); 5647 if (rank == 0) { 5648 char format[PETSC_MAX_PATH_LEN]; 5649 double x[3]; 5650 int l, val[3]; 5651 5652 if (Nl) { 5653 for (l = 0; l < Nl; ++l) { 5654 format[l * 3 + 0] = '%'; 5655 format[l * 3 + 1] = 'd'; 5656 format[l * 3 + 2] = ' '; 5657 } 5658 format[Nl * 3 - 1] = '\0'; 5659 PetscCall(DMCreateLabel(*dm, "marker")); 5660 PetscCall(DMGetLabel(*dm, "marker", &marker)); 5661 } 5662 for (v = 0; v < Nv; ++v) { 5663 PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING)); 5664 snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]); 5665 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5666 switch (Nl) { 5667 case 0: 5668 snum = 0; 5669 break; 5670 case 1: 5671 snum = sscanf(line, format, &val[0]); 5672 break; 5673 case 2: 5674 snum = sscanf(line, format, &val[0], &val[1]); 5675 break; 5676 case 3: 5677 snum = sscanf(line, format, &val[0], &val[1], &val[2]); 5678 break; 5679 default: 5680 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl); 5681 } 5682 PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 5683 for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d]; 5684 for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l])); 5685 } 5686 } 5687 PetscCall(VecRestoreArray(coordinates, &coords)); 5688 PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 5689 PetscCall(VecDestroy(&coordinates)); 5690 PetscCall(PetscViewerDestroy(&viewer)); 5691 if (interpolate) { 5692 DM idm; 5693 DMLabel bdlabel; 5694 5695 PetscCall(DMPlexInterpolate(*dm, &idm)); 5696 PetscCall(DMDestroy(dm)); 5697 *dm = idm; 5698 5699 if (!Nl) { 5700 PetscCall(DMCreateLabel(*dm, "marker")); 5701 PetscCall(DMGetLabel(*dm, "marker", &bdlabel)); 5702 PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel)); 5703 PetscCall(DMPlexLabelComplete(*dm, bdlabel)); 5704 } 5705 } 5706 PetscFunctionReturn(PETSC_SUCCESS); 5707 } 5708 5709 /*@ 5710 DMPlexCreateFromFile - This takes a filename and produces a `DM` 5711 5712 Collective 5713 5714 Input Parameters: 5715 + comm - The communicator 5716 . filename - A file name 5717 . plexname - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats 5718 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 5719 5720 Output Parameter: 5721 . dm - The `DM` 5722 5723 Options Database Key: 5724 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5 5725 5726 Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. 5727 $ -dm_plex_create_viewer_hdf5_collective 5728 5729 Level: beginner 5730 5731 Notes: 5732 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 5733 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 5734 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 5735 The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally 5736 calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats. 5737 5738 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()` 5739 @*/ 5740 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm) 5741 { 5742 const char extGmsh[] = ".msh"; 5743 const char extGmsh2[] = ".msh2"; 5744 const char extGmsh4[] = ".msh4"; 5745 const char extCGNS[] = ".cgns"; 5746 const char extExodus[] = ".exo"; 5747 const char extExodus_e[] = ".e"; 5748 const char extGenesis[] = ".gen"; 5749 const char extFluent[] = ".cas"; 5750 const char extHDF5[] = ".h5"; 5751 const char extXDMFHDF5[] = ".xdmf.h5"; 5752 const char extPLY[] = ".ply"; 5753 const char extEGADSLite[] = ".egadslite"; 5754 const char extEGADS[] = ".egads"; 5755 const char extIGES[] = ".igs"; 5756 const char extSTEP[] = ".stp"; 5757 const char extCV[] = ".dat"; 5758 size_t len; 5759 PetscBool isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSLite, isEGADS, isIGES, isSTEP, isCV, isXDMFHDF5; 5760 PetscMPIInt rank; 5761 5762 PetscFunctionBegin; 5763 PetscAssertPointer(filename, 2); 5764 if (plexname) PetscAssertPointer(plexname, 3); 5765 PetscAssertPointer(dm, 5); 5766 PetscCall(DMInitializePackage()); 5767 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 5768 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5769 PetscCall(PetscStrlen(filename, &len)); 5770 PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path"); 5771 5772 #define CheckExtension(extension__, is_extension__) \ 5773 do { \ 5774 PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \ 5775 /* don't count the null-terminator at the end */ \ 5776 const size_t ext_len = sizeof(extension__) - 1; \ 5777 if (len < ext_len) { \ 5778 is_extension__ = PETSC_FALSE; \ 5779 } else { \ 5780 PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \ 5781 } \ 5782 } while (0) 5783 5784 CheckExtension(extGmsh, isGmsh); 5785 CheckExtension(extGmsh2, isGmsh2); 5786 CheckExtension(extGmsh4, isGmsh4); 5787 CheckExtension(extCGNS, isCGNS); 5788 CheckExtension(extExodus, isExodus); 5789 if (!isExodus) CheckExtension(extExodus_e, isExodus); 5790 CheckExtension(extGenesis, isGenesis); 5791 CheckExtension(extFluent, isFluent); 5792 CheckExtension(extHDF5, isHDF5); 5793 CheckExtension(extPLY, isPLY); 5794 CheckExtension(extEGADSLite, isEGADSLite); 5795 CheckExtension(extEGADS, isEGADS); 5796 CheckExtension(extIGES, isIGES); 5797 CheckExtension(extSTEP, isSTEP); 5798 CheckExtension(extCV, isCV); 5799 CheckExtension(extXDMFHDF5, isXDMFHDF5); 5800 5801 #undef CheckExtension 5802 5803 if (isGmsh || isGmsh2 || isGmsh4) { 5804 PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm)); 5805 } else if (isCGNS) { 5806 PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm)); 5807 } else if (isExodus || isGenesis) { 5808 PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm)); 5809 } else if (isFluent) { 5810 PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm)); 5811 } else if (isHDF5) { 5812 PetscViewer viewer; 5813 5814 /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */ 5815 PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL)); 5816 PetscCall(PetscViewerCreate(comm, &viewer)); 5817 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5)); 5818 PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_")); 5819 PetscCall(PetscViewerSetFromOptions(viewer)); 5820 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 5821 PetscCall(PetscViewerFileSetName(viewer, filename)); 5822 5823 PetscCall(DMCreate(comm, dm)); 5824 PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 5825 PetscCall(DMSetType(*dm, DMPLEX)); 5826 if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF)); 5827 PetscCall(DMLoad(*dm, viewer)); 5828 if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer)); 5829 PetscCall(PetscViewerDestroy(&viewer)); 5830 5831 if (interpolate) { 5832 DM idm; 5833 5834 PetscCall(DMPlexInterpolate(*dm, &idm)); 5835 PetscCall(DMDestroy(dm)); 5836 *dm = idm; 5837 } 5838 } else if (isPLY) { 5839 PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm)); 5840 } else if (isEGADSLite || isEGADS || isIGES || isSTEP) { 5841 if (isEGADSLite) PetscCall(DMPlexCreateEGADSLiteFromFile(comm, filename, dm)); 5842 else PetscCall(DMPlexCreateEGADSFromFile(comm, filename, dm)); 5843 if (!interpolate) { 5844 DM udm; 5845 5846 PetscCall(DMPlexUninterpolate(*dm, &udm)); 5847 PetscCall(DMDestroy(dm)); 5848 *dm = udm; 5849 } 5850 } else if (isCV) { 5851 PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm)); 5852 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename); 5853 PetscCall(PetscStrlen(plexname, &len)); 5854 if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 5855 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 5856 PetscFunctionReturn(PETSC_SUCCESS); 5857 } 5858 5859 /*@ 5860 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. 5861 5862 Input Parameters: 5863 + tr - The `DMPlexTransform` 5864 - prefix - An options prefix, or NULL 5865 5866 Output Parameter: 5867 . dm - The `DM` 5868 5869 Level: beginner 5870 5871 Notes: 5872 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. 5873 5874 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 5875 @*/ 5876 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm) 5877 { 5878 DM bdm, bcdm, cdm; 5879 Vec coordinates, coordinatesNew; 5880 PetscSection cs; 5881 PetscInt dim, cdim, Nl; 5882 5883 PetscFunctionBegin; 5884 PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm)); 5885 PetscCall(DMSetType(*dm, DMPLEX)); 5886 ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL; 5887 // Handle coordinates 5888 PetscCall(DMPlexTransformGetDM(tr, &bdm)); 5889 PetscCall(DMGetCoordinateDim(bdm, &cdim)); 5890 PetscCall(DMSetCoordinateDim(*dm, cdim)); 5891 PetscCall(DMGetDimension(bdm, &dim)); 5892 PetscCall(DMSetDimension(*dm, dim)); 5893 PetscCall(DMGetCoordinateDM(bdm, &bcdm)); 5894 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 5895 PetscCall(DMCopyDisc(bcdm, cdm)); 5896 PetscCall(DMGetLocalSection(cdm, &cs)); 5897 PetscCall(PetscSectionSetNumFields(cs, 1)); 5898 PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim)); 5899 PetscCall(DMGetCoordinatesLocal(bdm, &coordinates)); 5900 PetscCall(VecDuplicate(coordinates, &coordinatesNew)); 5901 PetscCall(VecCopy(coordinates, coordinatesNew)); 5902 PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew)); 5903 PetscCall(VecDestroy(&coordinatesNew)); 5904 5905 PetscCall(PetscObjectReference((PetscObject)tr)); 5906 PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr)); 5907 ((DM_Plex *)(*dm)->data)->tr = tr; 5908 PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE)); 5909 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix)); 5910 PetscCall(DMSetFromOptions(*dm)); 5911 5912 PetscCall(DMGetNumLabels(bdm, &Nl)); 5913 for (PetscInt l = 0; l < Nl; ++l) { 5914 DMLabel label, labelNew; 5915 const char *lname; 5916 PetscBool isDepth, isCellType; 5917 5918 PetscCall(DMGetLabelName(bdm, l, &lname)); 5919 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 5920 if (isDepth) continue; 5921 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 5922 if (isCellType) continue; 5923 PetscCall(DMCreateLabel(*dm, lname)); 5924 PetscCall(DMGetLabel(bdm, lname, &label)); 5925 PetscCall(DMGetLabel(*dm, lname, &labelNew)); 5926 PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL)); 5927 PetscCall(DMLabelEphemeralSetLabel(labelNew, label)); 5928 PetscCall(DMLabelEphemeralSetTransform(labelNew, tr)); 5929 PetscCall(DMLabelSetUp(labelNew)); 5930 } 5931 PetscFunctionReturn(PETSC_SUCCESS); 5932 } 5933