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