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