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 DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], const DMBoundaryType bd[]) 1681 { 1682 Vec coordinates; 1683 PetscSection coordSection; 1684 DMLabel cutLabel = NULL; 1685 PetscBool cutMarker = PETSC_FALSE; 1686 PetscBool periodic = PETSC_FALSE; 1687 PetscInt numCells = 1, c; 1688 PetscInt numVertices = 1, v; 1689 PetscScalar *coords; 1690 PetscInt *vertices, *vert, *vtmp, *supp, cone[2]; 1691 PetscInt d, e, cell = 0, coordSize; 1692 PetscMPIInt rank; 1693 1694 PetscFunctionBegin; 1695 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1696 PetscCall(DMSetDimension(dm, dim)); 1697 PetscCall(PetscCalloc4(dim, &vertices, dim, &vert, dim, &vtmp, 2 * dim, &supp)); 1698 PetscCall(DMCreateLabel(dm, "marker")); 1699 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL)); 1700 for (d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE; 1701 if (periodic && cutMarker) { 1702 PetscCall(DMCreateLabel(dm, "periodic_cut")); 1703 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 1704 } 1705 for (d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Hypercubic mesh must be periodic now"); 1706 for (d = 0; d < dim; ++d) { 1707 vertices[d] = edges[d]; 1708 numVertices *= vertices[d]; 1709 } 1710 numCells = numVertices * dim; 1711 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 1712 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2)); 1713 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim)); 1714 /* TODO Loop over boundary and reset support sizes */ 1715 PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */ 1716 /* Build cell cones and vertex supports */ 1717 PetscCall(DMCreateLabel(dm, "celltype")); 1718 while (vert[dim - 1] < vertices[dim - 1]) { 1719 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells; 1720 PetscInt s = 0; 1721 1722 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex)); 1723 for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d])); 1724 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1725 PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT)); 1726 for (d = 0; d < dim; ++d) { 1727 for (e = 0; e < dim; ++e) vtmp[e] = vert[e]; 1728 vtmp[d] = (vert[d] + 1) % vertices[d]; 1729 cone[0] = vertex; 1730 cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells; 1731 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Vertex %" PetscInt_FMT ":", cone[1])); 1732 for (e = 0; e < dim; ++e) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vtmp[e])); 1733 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1734 PetscCall(DMPlexSetCone(dm, cell, cone)); 1735 PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT)); 1736 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1])); 1737 ++cell; 1738 } 1739 for (d = 0; d < dim; ++d) { 1740 for (e = 0; e < dim; ++e) vtmp[e] = vert[e]; 1741 vtmp[d] = (vert[d] + vertices[d] - 1) % vertices[d]; 1742 supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d; 1743 supp[s++] = (vertex - numCells) * dim + d; 1744 PetscCall(DMPlexSetSupport(dm, vertex, supp)); 1745 } 1746 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 1747 } 1748 PetscCall(DMPlexStratify(dm)); 1749 /* Build coordinates */ 1750 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1751 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1752 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 1753 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 1754 for (v = numCells; v < numCells + numVertices; ++v) { 1755 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 1756 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 1757 } 1758 PetscCall(PetscSectionSetUp(coordSection)); 1759 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 1760 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 1761 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 1762 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 1763 PetscCall(VecSetBlockSize(coordinates, dim)); 1764 PetscCall(VecSetType(coordinates, VECSTANDARD)); 1765 PetscCall(VecGetArray(coordinates, &coords)); 1766 for (d = 0; d < dim; ++d) vert[d] = 0; 1767 while (vert[dim - 1] < vertices[dim - 1]) { 1768 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert); 1769 1770 for (d = 0; d < dim; ++d) coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / vertices[d]) * vert[d]; 1771 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex)); 1772 for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d])); 1773 for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(coords[vertex * dim + d]))); 1774 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1775 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 1776 } 1777 PetscCall(VecRestoreArray(coordinates, &coords)); 1778 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1779 PetscCall(VecDestroy(&coordinates)); 1780 PetscCall(PetscFree4(vertices, vert, vtmp, supp)); 1781 //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper)); 1782 // Attach the extent 1783 { 1784 PetscContainer c; 1785 PetscInt *extent; 1786 1787 PetscCall(PetscMalloc1(dim, &extent)); 1788 for (PetscInt d = 0; d < dim; ++d) extent[d] = edges[d]; 1789 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c)); 1790 PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault)); 1791 PetscCall(PetscContainerSetPointer(c, extent)); 1792 PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c)); 1793 PetscCall(PetscContainerDestroy(&c)); 1794 } 1795 PetscFunctionReturn(PETSC_SUCCESS); 1796 } 1797 1798 /*@C 1799 DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges. 1800 1801 Collective 1802 1803 Input Parameters: 1804 + comm - The communicator for the DM object 1805 . dim - The spatial dimension 1806 . edges - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 1807 . lower - The lower left corner, or `NULL` for (0, 0, 0) 1808 - upper - The upper right corner, or `NULL` for (1, 1, 1) 1809 1810 Output Parameter: 1811 . dm - The DM object 1812 1813 Level: beginner 1814 1815 Note: 1816 If you want to customize this mesh using options, you just need to 1817 .vb 1818 DMCreate(comm, &dm); 1819 DMSetType(dm, DMPLEX); 1820 DMSetFromOptions(dm); 1821 .ve 1822 and use the options on the `DMSetFromOptions()` page. 1823 1824 The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively, 1825 .vb 1826 18--0-19--2-20--4-18 1827 | | | | 1828 13 15 17 13 1829 | | | | 1830 24-12-25-14-26-16-24 1831 | | | | 1832 7 9 11 7 1833 | | | | 1834 21--6-22--8-23-10-21 1835 | | | | 1836 1 3 5 1 1837 | | | | 1838 18--0-19--2-20--4-18 1839 .ve 1840 1841 .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()` 1842 @*/ 1843 PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], DM *dm) 1844 { 1845 PetscInt *edg; 1846 PetscReal *low, *upp; 1847 DMBoundaryType *bdt; 1848 PetscInt d; 1849 1850 PetscFunctionBegin; 1851 PetscCall(DMCreate(comm, dm)); 1852 PetscCall(DMSetType(*dm, DMPLEX)); 1853 PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt)); 1854 for (d = 0; d < dim; ++d) { 1855 edg[d] = edges ? edges[d] : 1; 1856 low[d] = lower ? lower[d] : 0.; 1857 upp[d] = upper ? upper[d] : 1.; 1858 bdt[d] = DM_BOUNDARY_PERIODIC; 1859 } 1860 PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, bdt)); 1861 PetscCall(PetscFree4(edg, low, upp, bdt)); 1862 PetscFunctionReturn(PETSC_SUCCESS); 1863 } 1864 1865 /*@ 1866 DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database. 1867 1868 Logically Collective 1869 1870 Input Parameters: 1871 + dm - the `DM` context 1872 - prefix - the prefix to prepend to all option names 1873 1874 Level: advanced 1875 1876 Note: 1877 A hyphen (-) must NOT be given at the beginning of the prefix name. 1878 The first character of all runtime options is AUTOMATICALLY the hyphen. 1879 1880 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()` 1881 @*/ 1882 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[]) 1883 { 1884 DM_Plex *mesh = (DM_Plex *)dm->data; 1885 1886 PetscFunctionBegin; 1887 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1888 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix)); 1889 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix)); 1890 PetscFunctionReturn(PETSC_SUCCESS); 1891 } 1892 1893 /* Remap geometry to cylinder 1894 TODO: This only works for a single refinement, then it is broken 1895 1896 Interior square: Linear interpolation is correct 1897 The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing 1898 such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance 1899 1900 phi = arctan(y/x) 1901 d_close = sqrt(1/8 + 1/4 sin^2(phi)) 1902 d_far = sqrt(1/2 + sin^2(phi)) 1903 1904 so we remap them using 1905 1906 x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close) 1907 y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close) 1908 1909 If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y. 1910 */ 1911 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[]) 1912 { 1913 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 1914 const PetscReal ds2 = 0.5 * dis; 1915 1916 if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) { 1917 f0[0] = u[0]; 1918 f0[1] = u[1]; 1919 } else { 1920 PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc; 1921 1922 x = PetscRealPart(u[0]); 1923 y = PetscRealPart(u[1]); 1924 phi = PetscAtan2Real(y, x); 1925 sinp = PetscSinReal(phi); 1926 cosp = PetscCosReal(phi); 1927 if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) { 1928 dc = PetscAbsReal(ds2 / sinp); 1929 df = PetscAbsReal(dis / sinp); 1930 xc = ds2 * x / PetscAbsReal(y); 1931 yc = ds2 * PetscSignReal(y); 1932 } else { 1933 dc = PetscAbsReal(ds2 / cosp); 1934 df = PetscAbsReal(dis / cosp); 1935 xc = ds2 * PetscSignReal(x); 1936 yc = ds2 * y / PetscAbsReal(x); 1937 } 1938 f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc); 1939 f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc); 1940 } 1941 f0[2] = u[2]; 1942 } 1943 1944 static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ, PetscInt Nr) 1945 { 1946 const PetscInt dim = 3; 1947 PetscInt numCells, numVertices; 1948 PetscMPIInt rank; 1949 1950 PetscFunctionBegin; 1951 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 1952 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1953 PetscCall(DMSetDimension(dm, dim)); 1954 /* Create topology */ 1955 { 1956 PetscInt cone[8], c; 1957 1958 numCells = rank == 0 ? 5 : 0; 1959 numVertices = rank == 0 ? 16 : 0; 1960 if (periodicZ == DM_BOUNDARY_PERIODIC) { 1961 numCells *= 3; 1962 numVertices = rank == 0 ? 24 : 0; 1963 } 1964 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 1965 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8)); 1966 PetscCall(DMSetUp(dm)); 1967 if (rank == 0) { 1968 if (periodicZ == DM_BOUNDARY_PERIODIC) { 1969 cone[0] = 15; 1970 cone[1] = 18; 1971 cone[2] = 17; 1972 cone[3] = 16; 1973 cone[4] = 31; 1974 cone[5] = 32; 1975 cone[6] = 33; 1976 cone[7] = 34; 1977 PetscCall(DMPlexSetCone(dm, 0, cone)); 1978 cone[0] = 16; 1979 cone[1] = 17; 1980 cone[2] = 24; 1981 cone[3] = 23; 1982 cone[4] = 32; 1983 cone[5] = 36; 1984 cone[6] = 37; 1985 cone[7] = 33; /* 22 25 26 21 */ 1986 PetscCall(DMPlexSetCone(dm, 1, cone)); 1987 cone[0] = 18; 1988 cone[1] = 27; 1989 cone[2] = 24; 1990 cone[3] = 17; 1991 cone[4] = 34; 1992 cone[5] = 33; 1993 cone[6] = 37; 1994 cone[7] = 38; 1995 PetscCall(DMPlexSetCone(dm, 2, cone)); 1996 cone[0] = 29; 1997 cone[1] = 27; 1998 cone[2] = 18; 1999 cone[3] = 15; 2000 cone[4] = 35; 2001 cone[5] = 31; 2002 cone[6] = 34; 2003 cone[7] = 38; 2004 PetscCall(DMPlexSetCone(dm, 3, cone)); 2005 cone[0] = 29; 2006 cone[1] = 15; 2007 cone[2] = 16; 2008 cone[3] = 23; 2009 cone[4] = 35; 2010 cone[5] = 36; 2011 cone[6] = 32; 2012 cone[7] = 31; 2013 PetscCall(DMPlexSetCone(dm, 4, cone)); 2014 2015 cone[0] = 31; 2016 cone[1] = 34; 2017 cone[2] = 33; 2018 cone[3] = 32; 2019 cone[4] = 19; 2020 cone[5] = 22; 2021 cone[6] = 21; 2022 cone[7] = 20; 2023 PetscCall(DMPlexSetCone(dm, 5, cone)); 2024 cone[0] = 32; 2025 cone[1] = 33; 2026 cone[2] = 37; 2027 cone[3] = 36; 2028 cone[4] = 22; 2029 cone[5] = 25; 2030 cone[6] = 26; 2031 cone[7] = 21; 2032 PetscCall(DMPlexSetCone(dm, 6, cone)); 2033 cone[0] = 34; 2034 cone[1] = 38; 2035 cone[2] = 37; 2036 cone[3] = 33; 2037 cone[4] = 20; 2038 cone[5] = 21; 2039 cone[6] = 26; 2040 cone[7] = 28; 2041 PetscCall(DMPlexSetCone(dm, 7, cone)); 2042 cone[0] = 35; 2043 cone[1] = 38; 2044 cone[2] = 34; 2045 cone[3] = 31; 2046 cone[4] = 30; 2047 cone[5] = 19; 2048 cone[6] = 20; 2049 cone[7] = 28; 2050 PetscCall(DMPlexSetCone(dm, 8, cone)); 2051 cone[0] = 35; 2052 cone[1] = 31; 2053 cone[2] = 32; 2054 cone[3] = 36; 2055 cone[4] = 30; 2056 cone[5] = 25; 2057 cone[6] = 22; 2058 cone[7] = 19; 2059 PetscCall(DMPlexSetCone(dm, 9, cone)); 2060 2061 cone[0] = 19; 2062 cone[1] = 20; 2063 cone[2] = 21; 2064 cone[3] = 22; 2065 cone[4] = 15; 2066 cone[5] = 16; 2067 cone[6] = 17; 2068 cone[7] = 18; 2069 PetscCall(DMPlexSetCone(dm, 10, cone)); 2070 cone[0] = 22; 2071 cone[1] = 21; 2072 cone[2] = 26; 2073 cone[3] = 25; 2074 cone[4] = 16; 2075 cone[5] = 23; 2076 cone[6] = 24; 2077 cone[7] = 17; 2078 PetscCall(DMPlexSetCone(dm, 11, cone)); 2079 cone[0] = 20; 2080 cone[1] = 28; 2081 cone[2] = 26; 2082 cone[3] = 21; 2083 cone[4] = 18; 2084 cone[5] = 17; 2085 cone[6] = 24; 2086 cone[7] = 27; 2087 PetscCall(DMPlexSetCone(dm, 12, cone)); 2088 cone[0] = 30; 2089 cone[1] = 28; 2090 cone[2] = 20; 2091 cone[3] = 19; 2092 cone[4] = 29; 2093 cone[5] = 15; 2094 cone[6] = 18; 2095 cone[7] = 27; 2096 PetscCall(DMPlexSetCone(dm, 13, cone)); 2097 cone[0] = 30; 2098 cone[1] = 19; 2099 cone[2] = 22; 2100 cone[3] = 25; 2101 cone[4] = 29; 2102 cone[5] = 23; 2103 cone[6] = 16; 2104 cone[7] = 15; 2105 PetscCall(DMPlexSetCone(dm, 14, cone)); 2106 } else { 2107 cone[0] = 5; 2108 cone[1] = 8; 2109 cone[2] = 7; 2110 cone[3] = 6; 2111 cone[4] = 9; 2112 cone[5] = 12; 2113 cone[6] = 11; 2114 cone[7] = 10; 2115 PetscCall(DMPlexSetCone(dm, 0, cone)); 2116 cone[0] = 6; 2117 cone[1] = 7; 2118 cone[2] = 14; 2119 cone[3] = 13; 2120 cone[4] = 12; 2121 cone[5] = 15; 2122 cone[6] = 16; 2123 cone[7] = 11; 2124 PetscCall(DMPlexSetCone(dm, 1, cone)); 2125 cone[0] = 8; 2126 cone[1] = 17; 2127 cone[2] = 14; 2128 cone[3] = 7; 2129 cone[4] = 10; 2130 cone[5] = 11; 2131 cone[6] = 16; 2132 cone[7] = 18; 2133 PetscCall(DMPlexSetCone(dm, 2, cone)); 2134 cone[0] = 19; 2135 cone[1] = 17; 2136 cone[2] = 8; 2137 cone[3] = 5; 2138 cone[4] = 20; 2139 cone[5] = 9; 2140 cone[6] = 10; 2141 cone[7] = 18; 2142 PetscCall(DMPlexSetCone(dm, 3, cone)); 2143 cone[0] = 19; 2144 cone[1] = 5; 2145 cone[2] = 6; 2146 cone[3] = 13; 2147 cone[4] = 20; 2148 cone[5] = 15; 2149 cone[6] = 12; 2150 cone[7] = 9; 2151 PetscCall(DMPlexSetCone(dm, 4, cone)); 2152 } 2153 } 2154 PetscCall(DMPlexSymmetrize(dm)); 2155 PetscCall(DMPlexStratify(dm)); 2156 } 2157 /* Create cube geometry */ 2158 { 2159 Vec coordinates; 2160 PetscSection coordSection; 2161 PetscScalar *coords; 2162 PetscInt coordSize, v; 2163 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 2164 const PetscReal ds2 = dis / 2.0; 2165 2166 /* Build coordinates */ 2167 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2168 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2169 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2170 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2171 for (v = numCells; v < numCells + numVertices; ++v) { 2172 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2173 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2174 } 2175 PetscCall(PetscSectionSetUp(coordSection)); 2176 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2177 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2178 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2179 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2180 PetscCall(VecSetBlockSize(coordinates, dim)); 2181 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2182 PetscCall(VecGetArray(coordinates, &coords)); 2183 if (rank == 0) { 2184 coords[0 * dim + 0] = -ds2; 2185 coords[0 * dim + 1] = -ds2; 2186 coords[0 * dim + 2] = 0.0; 2187 coords[1 * dim + 0] = ds2; 2188 coords[1 * dim + 1] = -ds2; 2189 coords[1 * dim + 2] = 0.0; 2190 coords[2 * dim + 0] = ds2; 2191 coords[2 * dim + 1] = ds2; 2192 coords[2 * dim + 2] = 0.0; 2193 coords[3 * dim + 0] = -ds2; 2194 coords[3 * dim + 1] = ds2; 2195 coords[3 * dim + 2] = 0.0; 2196 coords[4 * dim + 0] = -ds2; 2197 coords[4 * dim + 1] = -ds2; 2198 coords[4 * dim + 2] = 1.0; 2199 coords[5 * dim + 0] = -ds2; 2200 coords[5 * dim + 1] = ds2; 2201 coords[5 * dim + 2] = 1.0; 2202 coords[6 * dim + 0] = ds2; 2203 coords[6 * dim + 1] = ds2; 2204 coords[6 * dim + 2] = 1.0; 2205 coords[7 * dim + 0] = ds2; 2206 coords[7 * dim + 1] = -ds2; 2207 coords[7 * dim + 2] = 1.0; 2208 coords[8 * dim + 0] = dis; 2209 coords[8 * dim + 1] = -dis; 2210 coords[8 * dim + 2] = 0.0; 2211 coords[9 * dim + 0] = dis; 2212 coords[9 * dim + 1] = dis; 2213 coords[9 * dim + 2] = 0.0; 2214 coords[10 * dim + 0] = dis; 2215 coords[10 * dim + 1] = -dis; 2216 coords[10 * dim + 2] = 1.0; 2217 coords[11 * dim + 0] = dis; 2218 coords[11 * dim + 1] = dis; 2219 coords[11 * dim + 2] = 1.0; 2220 coords[12 * dim + 0] = -dis; 2221 coords[12 * dim + 1] = dis; 2222 coords[12 * dim + 2] = 0.0; 2223 coords[13 * dim + 0] = -dis; 2224 coords[13 * dim + 1] = dis; 2225 coords[13 * dim + 2] = 1.0; 2226 coords[14 * dim + 0] = -dis; 2227 coords[14 * dim + 1] = -dis; 2228 coords[14 * dim + 2] = 0.0; 2229 coords[15 * dim + 0] = -dis; 2230 coords[15 * dim + 1] = -dis; 2231 coords[15 * dim + 2] = 1.0; 2232 if (periodicZ == DM_BOUNDARY_PERIODIC) { 2233 /* 15 31 19 */ coords[16 * dim + 0] = -ds2; 2234 coords[16 * dim + 1] = -ds2; 2235 coords[16 * dim + 2] = 0.5; 2236 /* 16 32 22 */ coords[17 * dim + 0] = ds2; 2237 coords[17 * dim + 1] = -ds2; 2238 coords[17 * dim + 2] = 0.5; 2239 /* 17 33 21 */ coords[18 * dim + 0] = ds2; 2240 coords[18 * dim + 1] = ds2; 2241 coords[18 * dim + 2] = 0.5; 2242 /* 18 34 20 */ coords[19 * dim + 0] = -ds2; 2243 coords[19 * dim + 1] = ds2; 2244 coords[19 * dim + 2] = 0.5; 2245 /* 29 35 30 */ coords[20 * dim + 0] = -dis; 2246 coords[20 * dim + 1] = -dis; 2247 coords[20 * dim + 2] = 0.5; 2248 /* 23 36 25 */ coords[21 * dim + 0] = dis; 2249 coords[21 * dim + 1] = -dis; 2250 coords[21 * dim + 2] = 0.5; 2251 /* 24 37 26 */ coords[22 * dim + 0] = dis; 2252 coords[22 * dim + 1] = dis; 2253 coords[22 * dim + 2] = 0.5; 2254 /* 27 38 28 */ coords[23 * dim + 0] = -dis; 2255 coords[23 * dim + 1] = dis; 2256 coords[23 * dim + 2] = 0.5; 2257 } 2258 } 2259 PetscCall(VecRestoreArray(coordinates, &coords)); 2260 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2261 PetscCall(VecDestroy(&coordinates)); 2262 } 2263 /* Create periodicity */ 2264 if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) { 2265 PetscReal L[3] = {-1., -1., 0.}; 2266 PetscReal maxCell[3] = {-1., -1., 0.}; 2267 PetscReal lower[3] = {0.0, 0.0, 0.0}; 2268 PetscReal upper[3] = {1.0, 1.0, 1.5}; 2269 PetscInt numZCells = 3; 2270 2271 L[2] = upper[2] - lower[2]; 2272 maxCell[2] = 1.1 * (L[2] / numZCells); 2273 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 2274 } 2275 { 2276 DM cdm; 2277 PetscDS cds; 2278 PetscScalar c[2] = {1.0, 1.0}; 2279 2280 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 2281 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2282 PetscCall(DMGetDS(cdm, &cds)); 2283 PetscCall(PetscDSSetConstants(cds, 2, c)); 2284 } 2285 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 2286 2287 /* Wait for coordinate creation before doing in-place modification */ 2288 PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2289 2290 char oldprefix[PETSC_MAX_PATH_LEN]; 2291 const char *prefix; 2292 2293 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 2294 PetscCall(PetscStrncpy(oldprefix, prefix, PETSC_MAX_PATH_LEN)); 2295 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, "petsc_cyl_ref_")); 2296 for (PetscInt r = 0; r < PetscMax(0, Nr); ++r) { 2297 DM rdm; 2298 2299 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 2300 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 2301 } 2302 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldprefix)); 2303 PetscCall(DMPlexRemapGeometry(dm, 0.0, snapToCylinder)); 2304 2305 DMLabel bdlabel, edgelabel; 2306 IS faceIS; 2307 const PetscInt *faces; 2308 PetscInt Nf; 2309 2310 PetscCall(DMCreateLabel(dm, "marker")); 2311 PetscCall(DMGetLabel(dm, "marker", &bdlabel)); 2312 PetscCall(DMCreateLabel(dm, "generatrix")); 2313 PetscCall(DMGetLabel(dm, "generatrix", &edgelabel)); 2314 PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel)); 2315 // Remove faces on top and bottom 2316 PetscCall(DMLabelGetStratumIS(bdlabel, 1, &faceIS)); 2317 if (faceIS) { 2318 PetscCall(ISGetLocalSize(faceIS, &Nf)); 2319 PetscCall(ISGetIndices(faceIS, &faces)); 2320 for (PetscInt f = 0; f < Nf; ++f) { 2321 PetscReal vol, normal[3]; 2322 2323 PetscCall(DMPlexComputeCellGeometryFVM(dm, faces[f], &vol, NULL, normal)); 2324 if (PetscAbsReal(normal[2]) < PETSC_SMALL) PetscCall(DMLabelSetValue(edgelabel, faces[f], 1)); 2325 } 2326 PetscCall(ISRestoreIndices(faceIS, &faces)); 2327 PetscCall(ISDestroy(&faceIS)); 2328 } 2329 PetscCall(DMPlexLabelComplete(dm, bdlabel)); 2330 PetscCall(DMPlexLabelComplete(dm, edgelabel)); 2331 PetscFunctionReturn(PETSC_SUCCESS); 2332 } 2333 2334 /*@ 2335 DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra. 2336 2337 Collective 2338 2339 Input Parameters: 2340 + comm - The communicator for the `DM` object 2341 . periodicZ - The boundary type for the Z direction 2342 - Nr - The number of refinements to carry out 2343 2344 Output Parameter: 2345 . dm - The `DM` object 2346 2347 Level: beginner 2348 2349 Note: 2350 Here is the output numbering looking from the bottom of the cylinder\: 2351 .vb 2352 17-----14 2353 | | 2354 | 2 | 2355 | | 2356 17-----8-----7-----14 2357 | | | | 2358 | 3 | 0 | 1 | 2359 | | | | 2360 19-----5-----6-----13 2361 | | 2362 | 4 | 2363 | | 2364 19-----13 2365 2366 and up through the top 2367 2368 18-----16 2369 | | 2370 | 2 | 2371 | | 2372 18----10----11-----16 2373 | | | | 2374 | 3 | 0 | 1 | 2375 | | | | 2376 20-----9----12-----15 2377 | | 2378 | 4 | 2379 | | 2380 20-----15 2381 .ve 2382 2383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2384 @*/ 2385 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, PetscInt Nr, DM *dm) 2386 { 2387 PetscFunctionBegin; 2388 PetscAssertPointer(dm, 4); 2389 PetscCall(DMCreate(comm, dm)); 2390 PetscCall(DMSetType(*dm, DMPLEX)); 2391 PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ, Nr)); 2392 PetscFunctionReturn(PETSC_SUCCESS); 2393 } 2394 2395 static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate) 2396 { 2397 const PetscInt dim = 3; 2398 PetscInt numCells, numVertices, v; 2399 PetscMPIInt rank; 2400 2401 PetscFunctionBegin; 2402 PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n); 2403 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 2404 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2405 PetscCall(DMSetDimension(dm, dim)); 2406 /* Must create the celltype label here so that we do not automatically try to compute the types */ 2407 PetscCall(DMCreateLabel(dm, "celltype")); 2408 /* Create topology */ 2409 { 2410 PetscInt cone[6], c; 2411 2412 numCells = rank == 0 ? n : 0; 2413 numVertices = rank == 0 ? 2 * (n + 1) : 0; 2414 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 2415 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6)); 2416 PetscCall(DMSetUp(dm)); 2417 for (c = 0; c < numCells; c++) { 2418 cone[0] = c + n * 1; 2419 cone[1] = (c + 1) % n + n * 1; 2420 cone[2] = 0 + 3 * n; 2421 cone[3] = c + n * 2; 2422 cone[4] = (c + 1) % n + n * 2; 2423 cone[5] = 1 + 3 * n; 2424 PetscCall(DMPlexSetCone(dm, c, cone)); 2425 PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR)); 2426 } 2427 PetscCall(DMPlexSymmetrize(dm)); 2428 PetscCall(DMPlexStratify(dm)); 2429 } 2430 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT)); 2431 /* Create cylinder geometry */ 2432 { 2433 Vec coordinates; 2434 PetscSection coordSection; 2435 PetscScalar *coords; 2436 PetscInt coordSize, c; 2437 2438 /* Build coordinates */ 2439 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2440 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2441 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2442 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2443 for (v = numCells; v < numCells + numVertices; ++v) { 2444 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2445 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2446 } 2447 PetscCall(PetscSectionSetUp(coordSection)); 2448 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2449 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2450 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2451 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2452 PetscCall(VecSetBlockSize(coordinates, dim)); 2453 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2454 PetscCall(VecGetArray(coordinates, &coords)); 2455 for (c = 0; c < numCells; c++) { 2456 coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 2457 coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 2458 coords[(c + 0 * n) * dim + 2] = 1.0; 2459 coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 2460 coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 2461 coords[(c + 1 * n) * dim + 2] = 0.0; 2462 } 2463 if (rank == 0) { 2464 coords[(2 * n + 0) * dim + 0] = 0.0; 2465 coords[(2 * n + 0) * dim + 1] = 0.0; 2466 coords[(2 * n + 0) * dim + 2] = 1.0; 2467 coords[(2 * n + 1) * dim + 0] = 0.0; 2468 coords[(2 * n + 1) * dim + 1] = 0.0; 2469 coords[(2 * n + 1) * dim + 2] = 0.0; 2470 } 2471 PetscCall(VecRestoreArray(coordinates, &coords)); 2472 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2473 PetscCall(VecDestroy(&coordinates)); 2474 } 2475 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 2476 /* Interpolate */ 2477 if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2478 PetscFunctionReturn(PETSC_SUCCESS); 2479 } 2480 2481 /*@ 2482 DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges. 2483 2484 Collective 2485 2486 Input Parameters: 2487 + comm - The communicator for the `DM` object 2488 . n - The number of wedges around the origin 2489 - interpolate - Create edges and faces 2490 2491 Output Parameter: 2492 . dm - The `DM` object 2493 2494 Level: beginner 2495 2496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2497 @*/ 2498 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm) 2499 { 2500 PetscFunctionBegin; 2501 PetscAssertPointer(dm, 4); 2502 PetscCall(DMCreate(comm, dm)); 2503 PetscCall(DMSetType(*dm, DMPLEX)); 2504 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate)); 2505 PetscFunctionReturn(PETSC_SUCCESS); 2506 } 2507 2508 static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 2509 { 2510 PetscReal prod = 0.0; 2511 PetscInt i; 2512 for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]); 2513 return PetscSqrtReal(prod); 2514 } 2515 2516 static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 2517 { 2518 PetscReal prod = 0.0; 2519 PetscInt i; 2520 for (i = 0; i < dim; ++i) prod += x[i] * y[i]; 2521 return prod; 2522 } 2523 2524 /* The first constant is the sphere radius */ 2525 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[]) 2526 { 2527 PetscReal r = PetscRealPart(constants[0]); 2528 PetscReal norm2 = 0.0, fac; 2529 PetscInt n = uOff[1] - uOff[0], d; 2530 2531 for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d])); 2532 fac = r / PetscSqrtReal(norm2); 2533 for (d = 0; d < n; ++d) f0[d] = u[d] * fac; 2534 } 2535 2536 static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R) 2537 { 2538 const PetscInt embedDim = dim + 1; 2539 PetscSection coordSection; 2540 Vec coordinates; 2541 PetscScalar *coords; 2542 PetscReal *coordsIn; 2543 PetscInt numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e; 2544 PetscMPIInt rank; 2545 2546 PetscFunctionBegin; 2547 PetscValidLogicalCollectiveBool(dm, simplex, 3); 2548 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 2549 PetscCall(DMSetDimension(dm, dim)); 2550 PetscCall(DMSetCoordinateDim(dm, dim + 1)); 2551 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2552 switch (dim) { 2553 case 1: 2554 numCells = 16; 2555 numVerts = numCells; 2556 2557 // Build Topology 2558 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2559 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2560 PetscCall(DMSetUp(dm)); 2561 for (PetscInt c = 0; c < numCells; ++c) { 2562 PetscInt cone[2]; 2563 2564 cone[0] = c + numCells; 2565 cone[1] = (c + 1) % numVerts + numCells; 2566 PetscCall(DMPlexSetCone(dm, c, cone)); 2567 } 2568 PetscCall(DMPlexSymmetrize(dm)); 2569 PetscCall(DMPlexStratify(dm)); 2570 PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn)); 2571 for (PetscInt v = 0; v < numVerts; ++v) { 2572 const PetscReal rad = 2. * PETSC_PI * v / numVerts; 2573 2574 coordsIn[v * embedDim + 0] = PetscCosReal(rad); 2575 coordsIn[v * embedDim + 1] = PetscSinReal(rad); 2576 } 2577 break; 2578 case 2: 2579 if (simplex) { 2580 const PetscReal radius = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI); 2581 const PetscReal edgeLen = 2.0 / (1.0 + PETSC_PHI) * (R / radius); 2582 const PetscInt degree = 5; 2583 PetscReal vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)}; 2584 PetscInt s[3] = {1, 1, 1}; 2585 PetscInt cone[3]; 2586 PetscInt *graph; 2587 2588 vertex[0] *= R / radius; 2589 vertex[1] *= R / radius; 2590 vertex[2] *= R / radius; 2591 numCells = rank == 0 ? 20 : 0; 2592 numVerts = rank == 0 ? 12 : 0; 2593 firstVertex = numCells; 2594 /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of 2595 2596 (0, \pm 1/\phi+1, \pm \phi/\phi+1) 2597 2598 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 2599 length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393. 2600 */ 2601 /* Construct vertices */ 2602 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2603 if (rank == 0) { 2604 for (PetscInt p = 0, i = 0; p < embedDim; ++p) { 2605 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2606 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2607 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim]; 2608 ++i; 2609 } 2610 } 2611 } 2612 } 2613 /* Construct graph */ 2614 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 2615 for (PetscInt i = 0; i < numVerts; ++i) { 2616 PetscInt k = 0; 2617 for (PetscInt j = 0; j < numVerts; ++j) { 2618 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 2619 graph[i * numVerts + j] = 1; 2620 ++k; 2621 } 2622 } 2623 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 2624 } 2625 /* Build Topology */ 2626 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2627 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2628 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2629 /* Cells */ 2630 for (PetscInt i = 0, c = 0; i < numVerts; ++i) { 2631 for (PetscInt j = 0; j < i; ++j) { 2632 for (PetscInt k = 0; k < j; ++k) { 2633 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) { 2634 cone[0] = firstVertex + i; 2635 cone[1] = firstVertex + j; 2636 cone[2] = firstVertex + k; 2637 /* Check orientation */ 2638 { 2639 const PetscInt epsilon[3][3][3] = { 2640 {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 2641 {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 2642 {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 2643 }; 2644 PetscReal normal[3]; 2645 PetscInt e, f; 2646 2647 for (d = 0; d < embedDim; ++d) { 2648 normal[d] = 0.0; 2649 for (e = 0; e < embedDim; ++e) { 2650 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]); 2651 } 2652 } 2653 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 2654 PetscInt tmp = cone[1]; 2655 cone[1] = cone[2]; 2656 cone[2] = tmp; 2657 } 2658 } 2659 PetscCall(DMPlexSetCone(dm, c++, cone)); 2660 } 2661 } 2662 } 2663 } 2664 PetscCall(DMPlexSymmetrize(dm)); 2665 PetscCall(DMPlexStratify(dm)); 2666 PetscCall(PetscFree(graph)); 2667 } else { 2668 /* 2669 12-21--13 2670 | | 2671 25 4 24 2672 | | 2673 12-25--9-16--8-24--13 2674 | | | | 2675 23 5 17 0 15 3 22 2676 | | | | 2677 10-20--6-14--7-19--11 2678 | | 2679 20 1 19 2680 | | 2681 10-18--11 2682 | | 2683 23 2 22 2684 | | 2685 12-21--13 2686 */ 2687 PetscInt cone[4], ornt[4]; 2688 2689 numCells = rank == 0 ? 6 : 0; 2690 numEdges = rank == 0 ? 12 : 0; 2691 numVerts = rank == 0 ? 8 : 0; 2692 firstVertex = numCells; 2693 firstEdge = numCells + numVerts; 2694 /* Build Topology */ 2695 PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts)); 2696 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4)); 2697 for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 2698 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2699 if (rank == 0) { 2700 /* Cell 0 */ 2701 cone[0] = 14; 2702 cone[1] = 15; 2703 cone[2] = 16; 2704 cone[3] = 17; 2705 PetscCall(DMPlexSetCone(dm, 0, cone)); 2706 ornt[0] = 0; 2707 ornt[1] = 0; 2708 ornt[2] = 0; 2709 ornt[3] = 0; 2710 PetscCall(DMPlexSetConeOrientation(dm, 0, ornt)); 2711 /* Cell 1 */ 2712 cone[0] = 18; 2713 cone[1] = 19; 2714 cone[2] = 14; 2715 cone[3] = 20; 2716 PetscCall(DMPlexSetCone(dm, 1, cone)); 2717 ornt[0] = 0; 2718 ornt[1] = 0; 2719 ornt[2] = -1; 2720 ornt[3] = 0; 2721 PetscCall(DMPlexSetConeOrientation(dm, 1, ornt)); 2722 /* Cell 2 */ 2723 cone[0] = 21; 2724 cone[1] = 22; 2725 cone[2] = 18; 2726 cone[3] = 23; 2727 PetscCall(DMPlexSetCone(dm, 2, cone)); 2728 ornt[0] = 0; 2729 ornt[1] = 0; 2730 ornt[2] = -1; 2731 ornt[3] = 0; 2732 PetscCall(DMPlexSetConeOrientation(dm, 2, ornt)); 2733 /* Cell 3 */ 2734 cone[0] = 19; 2735 cone[1] = 22; 2736 cone[2] = 24; 2737 cone[3] = 15; 2738 PetscCall(DMPlexSetCone(dm, 3, cone)); 2739 ornt[0] = -1; 2740 ornt[1] = -1; 2741 ornt[2] = 0; 2742 ornt[3] = -1; 2743 PetscCall(DMPlexSetConeOrientation(dm, 3, ornt)); 2744 /* Cell 4 */ 2745 cone[0] = 16; 2746 cone[1] = 24; 2747 cone[2] = 21; 2748 cone[3] = 25; 2749 PetscCall(DMPlexSetCone(dm, 4, cone)); 2750 ornt[0] = -1; 2751 ornt[1] = -1; 2752 ornt[2] = -1; 2753 ornt[3] = 0; 2754 PetscCall(DMPlexSetConeOrientation(dm, 4, ornt)); 2755 /* Cell 5 */ 2756 cone[0] = 20; 2757 cone[1] = 17; 2758 cone[2] = 25; 2759 cone[3] = 23; 2760 PetscCall(DMPlexSetCone(dm, 5, cone)); 2761 ornt[0] = -1; 2762 ornt[1] = -1; 2763 ornt[2] = -1; 2764 ornt[3] = -1; 2765 PetscCall(DMPlexSetConeOrientation(dm, 5, ornt)); 2766 /* Edges */ 2767 cone[0] = 6; 2768 cone[1] = 7; 2769 PetscCall(DMPlexSetCone(dm, 14, cone)); 2770 cone[0] = 7; 2771 cone[1] = 8; 2772 PetscCall(DMPlexSetCone(dm, 15, cone)); 2773 cone[0] = 8; 2774 cone[1] = 9; 2775 PetscCall(DMPlexSetCone(dm, 16, cone)); 2776 cone[0] = 9; 2777 cone[1] = 6; 2778 PetscCall(DMPlexSetCone(dm, 17, cone)); 2779 cone[0] = 10; 2780 cone[1] = 11; 2781 PetscCall(DMPlexSetCone(dm, 18, cone)); 2782 cone[0] = 11; 2783 cone[1] = 7; 2784 PetscCall(DMPlexSetCone(dm, 19, cone)); 2785 cone[0] = 6; 2786 cone[1] = 10; 2787 PetscCall(DMPlexSetCone(dm, 20, cone)); 2788 cone[0] = 12; 2789 cone[1] = 13; 2790 PetscCall(DMPlexSetCone(dm, 21, cone)); 2791 cone[0] = 13; 2792 cone[1] = 11; 2793 PetscCall(DMPlexSetCone(dm, 22, cone)); 2794 cone[0] = 10; 2795 cone[1] = 12; 2796 PetscCall(DMPlexSetCone(dm, 23, cone)); 2797 cone[0] = 13; 2798 cone[1] = 8; 2799 PetscCall(DMPlexSetCone(dm, 24, cone)); 2800 cone[0] = 12; 2801 cone[1] = 9; 2802 PetscCall(DMPlexSetCone(dm, 25, cone)); 2803 } 2804 PetscCall(DMPlexSymmetrize(dm)); 2805 PetscCall(DMPlexStratify(dm)); 2806 /* Build coordinates */ 2807 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2808 if (rank == 0) { 2809 coordsIn[0 * embedDim + 0] = -R; 2810 coordsIn[0 * embedDim + 1] = R; 2811 coordsIn[0 * embedDim + 2] = -R; 2812 coordsIn[1 * embedDim + 0] = R; 2813 coordsIn[1 * embedDim + 1] = R; 2814 coordsIn[1 * embedDim + 2] = -R; 2815 coordsIn[2 * embedDim + 0] = R; 2816 coordsIn[2 * embedDim + 1] = -R; 2817 coordsIn[2 * embedDim + 2] = -R; 2818 coordsIn[3 * embedDim + 0] = -R; 2819 coordsIn[3 * embedDim + 1] = -R; 2820 coordsIn[3 * embedDim + 2] = -R; 2821 coordsIn[4 * embedDim + 0] = -R; 2822 coordsIn[4 * embedDim + 1] = R; 2823 coordsIn[4 * embedDim + 2] = R; 2824 coordsIn[5 * embedDim + 0] = R; 2825 coordsIn[5 * embedDim + 1] = R; 2826 coordsIn[5 * embedDim + 2] = R; 2827 coordsIn[6 * embedDim + 0] = -R; 2828 coordsIn[6 * embedDim + 1] = -R; 2829 coordsIn[6 * embedDim + 2] = R; 2830 coordsIn[7 * embedDim + 0] = R; 2831 coordsIn[7 * embedDim + 1] = -R; 2832 coordsIn[7 * embedDim + 2] = R; 2833 } 2834 } 2835 break; 2836 case 3: 2837 if (simplex) { 2838 const PetscReal edgeLen = 1.0 / PETSC_PHI; 2839 PetscReal vertexA[4] = {0.5, 0.5, 0.5, 0.5}; 2840 PetscReal vertexB[4] = {1.0, 0.0, 0.0, 0.0}; 2841 PetscReal vertexC[4] = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0}; 2842 const PetscInt degree = 12; 2843 PetscInt s[4] = {1, 1, 1}; 2844 PetscInt evenPerm[12][4] = { 2845 {0, 1, 2, 3}, 2846 {0, 2, 3, 1}, 2847 {0, 3, 1, 2}, 2848 {1, 0, 3, 2}, 2849 {1, 2, 0, 3}, 2850 {1, 3, 2, 0}, 2851 {2, 0, 1, 3}, 2852 {2, 1, 3, 0}, 2853 {2, 3, 0, 1}, 2854 {3, 0, 2, 1}, 2855 {3, 1, 0, 2}, 2856 {3, 2, 1, 0} 2857 }; 2858 PetscInt cone[4]; 2859 PetscInt *graph, p, i, j, k, l; 2860 2861 vertexA[0] *= R; 2862 vertexA[1] *= R; 2863 vertexA[2] *= R; 2864 vertexA[3] *= R; 2865 vertexB[0] *= R; 2866 vertexB[1] *= R; 2867 vertexB[2] *= R; 2868 vertexB[3] *= R; 2869 vertexC[0] *= R; 2870 vertexC[1] *= R; 2871 vertexC[2] *= R; 2872 vertexC[3] *= R; 2873 numCells = rank == 0 ? 600 : 0; 2874 numVerts = rank == 0 ? 120 : 0; 2875 firstVertex = numCells; 2876 /* Use the 600-cell, which for a unit sphere has coordinates which are 2877 2878 1/2 (\pm 1, \pm 1, \pm 1, \pm 1) 16 2879 (\pm 1, 0, 0, 0) all cyclic permutations 8 2880 1/2 (\pm 1, \pm phi, \pm 1/phi, 0) all even permutations 96 2881 2882 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 2883 length is then given by 1/\phi = 0.61803. 2884 2885 http://buzzard.pugetsound.edu/sage-practice/ch03s03.html 2886 http://mathworld.wolfram.com/600-Cell.html 2887 */ 2888 /* Construct vertices */ 2889 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 2890 i = 0; 2891 if (rank == 0) { 2892 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2893 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2894 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2895 for (s[3] = -1; s[3] < 2; s[3] += 2) { 2896 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d]; 2897 ++i; 2898 } 2899 } 2900 } 2901 } 2902 for (p = 0; p < embedDim; ++p) { 2903 s[1] = s[2] = s[3] = 1; 2904 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2905 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim]; 2906 ++i; 2907 } 2908 } 2909 for (p = 0; p < 12; ++p) { 2910 s[3] = 1; 2911 for (s[0] = -1; s[0] < 2; s[0] += 2) { 2912 for (s[1] = -1; s[1] < 2; s[1] += 2) { 2913 for (s[2] = -1; s[2] < 2; s[2] += 2) { 2914 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]]; 2915 ++i; 2916 } 2917 } 2918 } 2919 } 2920 } 2921 PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts); 2922 /* Construct graph */ 2923 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 2924 for (i = 0; i < numVerts; ++i) { 2925 for (j = 0, k = 0; j < numVerts; ++j) { 2926 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 2927 graph[i * numVerts + j] = 1; 2928 ++k; 2929 } 2930 } 2931 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 2932 } 2933 /* Build Topology */ 2934 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 2935 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 2936 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 2937 /* Cells */ 2938 if (rank == 0) { 2939 for (PetscInt i = 0, c = 0; i < numVerts; ++i) { 2940 for (j = 0; j < i; ++j) { 2941 for (k = 0; k < j; ++k) { 2942 for (l = 0; l < k; ++l) { 2943 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]) { 2944 cone[0] = firstVertex + i; 2945 cone[1] = firstVertex + j; 2946 cone[2] = firstVertex + k; 2947 cone[3] = firstVertex + l; 2948 /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */ 2949 { 2950 const PetscInt epsilon[4][4][4][4] = { 2951 {{{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}}}, 2952 2953 {{{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}}}, 2954 2955 {{{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}}}, 2956 2957 {{{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}} } 2958 }; 2959 PetscReal normal[4]; 2960 PetscInt e, f, g; 2961 2962 for (d = 0; d < embedDim; ++d) { 2963 normal[d] = 0.0; 2964 for (e = 0; e < embedDim; ++e) { 2965 for (f = 0; f < embedDim; ++f) { 2966 for (g = 0; g < embedDim; ++g) { 2967 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]); 2968 } 2969 } 2970 } 2971 } 2972 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 2973 PetscInt tmp = cone[1]; 2974 cone[1] = cone[2]; 2975 cone[2] = tmp; 2976 } 2977 } 2978 PetscCall(DMPlexSetCone(dm, c++, cone)); 2979 } 2980 } 2981 } 2982 } 2983 } 2984 } 2985 PetscCall(DMPlexSymmetrize(dm)); 2986 PetscCall(DMPlexStratify(dm)); 2987 PetscCall(PetscFree(graph)); 2988 } 2989 break; 2990 default: 2991 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim); 2992 } 2993 /* Create coordinates */ 2994 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2995 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2996 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim)); 2997 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts)); 2998 for (v = firstVertex; v < firstVertex + numVerts; ++v) { 2999 PetscCall(PetscSectionSetDof(coordSection, v, embedDim)); 3000 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim)); 3001 } 3002 PetscCall(PetscSectionSetUp(coordSection)); 3003 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 3004 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 3005 PetscCall(VecSetBlockSize(coordinates, embedDim)); 3006 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 3007 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 3008 PetscCall(VecSetType(coordinates, VECSTANDARD)); 3009 PetscCall(VecGetArray(coordinates, &coords)); 3010 for (v = 0; v < numVerts; ++v) 3011 for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d]; 3012 PetscCall(VecRestoreArray(coordinates, &coords)); 3013 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 3014 PetscCall(VecDestroy(&coordinates)); 3015 PetscCall(PetscFree(coordsIn)); 3016 { 3017 DM cdm; 3018 PetscDS cds; 3019 PetscScalar c = R; 3020 3021 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToSphere)); 3022 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3023 PetscCall(DMGetDS(cdm, &cds)); 3024 PetscCall(PetscDSSetConstants(cds, 1, &c)); 3025 } 3026 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 3027 /* Wait for coordinate creation before doing in-place modification */ 3028 if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 3029 PetscFunctionReturn(PETSC_SUCCESS); 3030 } 3031 3032 typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]); 3033 3034 /* 3035 The Schwarz P implicit surface is 3036 3037 f(x) = cos(x0) + cos(x1) + cos(x2) = 0 3038 */ 3039 static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 3040 { 3041 PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)}; 3042 PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)}; 3043 f[0] = c[0] + c[1] + c[2]; 3044 for (PetscInt i = 0; i < 3; i++) { 3045 grad[i] = PETSC_PI * g[i]; 3046 for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.; 3047 } 3048 } 3049 3050 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 3051 static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 3052 { 3053 for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI); 3054 return PETSC_SUCCESS; 3055 } 3056 3057 /* 3058 The Gyroid implicit surface is 3059 3060 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) 3061 3062 */ 3063 static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 3064 { 3065 PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))}; 3066 PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))}; 3067 f[0] = s[0] * c[1] + s[1] * c[2] + s[2] * c[0]; 3068 grad[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 3069 grad[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 3070 grad[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 3071 hess[0][0] = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]); 3072 hess[0][1] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 3073 hess[0][2] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 3074 hess[1][0] = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]); 3075 hess[1][1] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 3076 hess[2][2] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 3077 hess[2][0] = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]); 3078 hess[2][1] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 3079 hess[2][2] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 3080 } 3081 3082 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 3083 static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 3084 { 3085 PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))}; 3086 PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))}; 3087 u[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 3088 u[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 3089 u[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 3090 return PETSC_SUCCESS; 3091 } 3092 3093 /* 3094 We wish to solve 3095 3096 min_y || y - x ||^2 subject to f(y) = 0 3097 3098 Let g(y) = grad(f). The minimization problem is equivalent to asking to satisfy 3099 f(y) = 0 and (y-x) is parallel to g(y). We do this by using Householder QR to obtain a basis for the 3100 tangent space and ask for both components in the tangent space to be zero. 3101 3102 Take g to be a column vector and compute the "full QR" factorization Q R = g, 3103 where Q = I - 2 n n^T is a symmetric orthogonal matrix. 3104 The first column of Q is parallel to g so the remaining two columns span the null space. 3105 Let Qn = Q[:,1:] be those remaining columns. Then Qn Qn^T is an orthogonal projector into the tangent space. 3106 Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries. 3107 In total, we have a system of 3 equations in 3 unknowns: 3108 3109 f(y) = 0 1 equation 3110 Qn^T (y - x) = 0 2 equations 3111 3112 Here, we compute the residual and Jacobian of this system. 3113 */ 3114 static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[]) 3115 { 3116 PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])}; 3117 PetscReal d[3] = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])}; 3118 PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign; 3119 PetscReal n_y[3][3] = { 3120 {0, 0, 0}, 3121 {0, 0, 0}, 3122 {0, 0, 0} 3123 }; 3124 3125 feval(yreal, &f, grad, n_y); 3126 3127 for (PetscInt i = 0; i < 3; i++) n[i] = grad[i]; 3128 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 3129 for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i]; 3130 3131 // Define the Householder reflector 3132 sign = n[0] >= 0 ? 1. : -1.; 3133 n[0] += norm * sign; 3134 for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign; 3135 3136 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 3137 norm_y[0] = 1. / norm * (n[0] * n_y[0][0]); 3138 norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]); 3139 norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]); 3140 3141 for (PetscInt i = 0; i < 3; i++) { 3142 n[i] /= norm; 3143 for (PetscInt j = 0; j < 3; j++) { 3144 // note that n[i] is n_old[i]/norm when executing the code below 3145 n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j]; 3146 } 3147 } 3148 3149 nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2]; 3150 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]; 3151 3152 res[0] = f; 3153 res[1] = d[1] - 2 * n[1] * nd; 3154 res[2] = d[2] - 2 * n[2] * nd; 3155 // J[j][i] is J_{ij} (column major) 3156 for (PetscInt j = 0; j < 3; j++) { 3157 J[0 + j * 3] = grad[j]; 3158 J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]); 3159 J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]); 3160 } 3161 } 3162 3163 /* 3164 Project x to the nearest point on the implicit surface using Newton's method. 3165 */ 3166 static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[]) 3167 { 3168 PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess 3169 3170 PetscFunctionBegin; 3171 for (PetscInt iter = 0; iter < 10; iter++) { 3172 PetscScalar res[3], J[9]; 3173 PetscReal resnorm; 3174 TPSNearestPointResJac(feval, x, y, res, J); 3175 resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2]))); 3176 if (0) { // Turn on this monitor if you need to confirm quadratic convergence 3177 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]))); 3178 } 3179 if (resnorm < PETSC_SMALL) break; 3180 3181 // Take the Newton step 3182 PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL)); 3183 PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res); 3184 } 3185 for (PetscInt i = 0; i < 3; i++) x[i] = y[i]; 3186 PetscFunctionReturn(PETSC_SUCCESS); 3187 } 3188 3189 const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL}; 3190 3191 static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness) 3192 { 3193 PetscMPIInt rank; 3194 PetscInt topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0; 3195 PetscInt(*edges)[2] = NULL, *edgeSets = NULL; 3196 PetscInt *cells_flat = NULL; 3197 PetscReal *vtxCoords = NULL; 3198 TPSEvaluateFunc evalFunc = NULL; 3199 PetscSimplePointFn *normalFunc = NULL; 3200 DMLabel label; 3201 3202 PetscFunctionBegin; 3203 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 3204 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3205 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); 3206 switch (tpstype) { 3207 case DMPLEX_TPS_SCHWARZ_P: 3208 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"); 3209 if (rank == 0) { 3210 PetscInt(*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn] 3211 PetscInt Njunctions = 0, Ncuts = 0, Npipes[3], vcount; 3212 PetscReal L = 1; 3213 3214 Npipes[0] = (extent[0] + 1) * extent[1] * extent[2]; 3215 Npipes[1] = extent[0] * (extent[1] + 1) * extent[2]; 3216 Npipes[2] = extent[0] * extent[1] * (extent[2] + 1); 3217 Njunctions = extent[0] * extent[1] * extent[2]; 3218 Ncuts = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]); 3219 numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions; 3220 PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords)); 3221 PetscCall(PetscMalloc1(Njunctions, &cells)); 3222 PetscCall(PetscMalloc1(Ncuts * 4, &edges)); 3223 PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets)); 3224 // x-normal pipes 3225 vcount = 0; 3226 for (PetscInt i = 0; i < extent[0] + 1; i++) { 3227 for (PetscInt j = 0; j < extent[1]; j++) { 3228 for (PetscInt k = 0; k < extent[2]; k++) { 3229 for (PetscInt l = 0; l < 4; l++) { 3230 vtxCoords[vcount++] = (2 * i - 1) * L; 3231 vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3232 vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3233 } 3234 } 3235 } 3236 } 3237 // y-normal pipes 3238 for (PetscInt i = 0; i < extent[0]; i++) { 3239 for (PetscInt j = 0; j < extent[1] + 1; j++) { 3240 for (PetscInt k = 0; k < extent[2]; k++) { 3241 for (PetscInt l = 0; l < 4; l++) { 3242 vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3243 vtxCoords[vcount++] = (2 * j - 1) * L; 3244 vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3245 } 3246 } 3247 } 3248 } 3249 // z-normal pipes 3250 for (PetscInt i = 0; i < extent[0]; i++) { 3251 for (PetscInt j = 0; j < extent[1]; j++) { 3252 for (PetscInt k = 0; k < extent[2] + 1; k++) { 3253 for (PetscInt l = 0; l < 4; l++) { 3254 vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3255 vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3256 vtxCoords[vcount++] = (2 * k - 1) * L; 3257 } 3258 } 3259 } 3260 } 3261 // junctions 3262 for (PetscInt i = 0; i < extent[0]; i++) { 3263 for (PetscInt j = 0; j < extent[1]; j++) { 3264 for (PetscInt k = 0; k < extent[2]; k++) { 3265 const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8; 3266 PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count"); 3267 for (PetscInt ii = 0; ii < 2; ii++) { 3268 for (PetscInt jj = 0; jj < 2; jj++) { 3269 for (PetscInt kk = 0; kk < 2; kk++) { 3270 double Ls = (1 - sqrt(2) / 4) * L; 3271 vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls; 3272 vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls; 3273 vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls; 3274 } 3275 } 3276 } 3277 const PetscInt jfaces[3][2][4] = { 3278 {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned 3279 {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned 3280 {{6, 2, 0, 4}, {7, 3, 1, 5}} // z-aligned 3281 }; 3282 const PetscInt pipe_lo[3] = {// vertex numbers of pipes 3283 ((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}; 3284 const PetscInt pipe_hi[3] = {// vertex numbers of pipes 3285 (((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}; 3286 for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z 3287 const PetscInt ijk[3] = {i, j, k}; 3288 for (PetscInt l = 0; l < 4; l++) { // rotations 3289 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l; 3290 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l]; 3291 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4]; 3292 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4; 3293 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l]; 3294 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l; 3295 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4; 3296 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4]; 3297 if (ijk[dir] == 0) { 3298 edges[numEdges][0] = pipe_lo[dir] + l; 3299 edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4; 3300 edgeSets[numEdges] = dir * 2 + 1; 3301 numEdges++; 3302 } 3303 if (ijk[dir] + 1 == extent[dir]) { 3304 edges[numEdges][0] = pipe_hi[dir] + l; 3305 edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4; 3306 edgeSets[numEdges] = dir * 2 + 2; 3307 numEdges++; 3308 } 3309 } 3310 } 3311 } 3312 } 3313 } 3314 PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts); 3315 numFaces = 24 * Njunctions; 3316 cells_flat = cells[0][0][0]; 3317 } 3318 evalFunc = TPSEvaluate_SchwarzP; 3319 normalFunc = TPSExtrudeNormalFunc_SchwarzP; 3320 break; 3321 case DMPLEX_TPS_GYROID: 3322 if (rank == 0) { 3323 // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set 3324 // 3325 // 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) 3326 // 3327 // on the cell [0,2]^3. 3328 // 3329 // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2]. 3330 // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins 3331 // like a boomerang: 3332 // 3333 // z = 0 z = 1/4 z = 1/2 z = 3/4 // 3334 // ----- ------- ------- ------- // 3335 // // 3336 // + + + + + + + \ + // 3337 // \ / \ // 3338 // \ `-_ _-' / } // 3339 // *-_ `-' _-' / // 3340 // + `-+ + + +-' + + / + // 3341 // // 3342 // // 3343 // z = 1 z = 5/4 z = 3/2 z = 7/4 // 3344 // ----- ------- ------- ------- // 3345 // // 3346 // +-_ + + + + _-+ + / + // 3347 // `-_ _-_ _-` / // 3348 // \ _-' `-_ / { // 3349 // \ / \ // 3350 // + + + + + + + \ + // 3351 // 3352 // 3353 // This course mesh approximates each of these slices by two line segments, 3354 // and then connects the segments in consecutive layers with quadrilateral faces. 3355 // All of the end points of the segments are multiples of 1/4 except for the 3356 // point * in the picture for z = 0 above and the similar points in other layers. 3357 // That point is at (gamma, gamma, 0), where gamma is calculated below. 3358 // 3359 // The column [1,2]x[1,2]x[0,2] looks the same as this column; 3360 // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images. 3361 // 3362 // As for how this method turned into the names given to the vertices: 3363 // that was not systematic, it was just the way it worked out in my handwritten notes. 3364 3365 PetscInt facesPerBlock = 64; 3366 PetscInt vertsPerBlock = 56; 3367 PetscInt extentPlus[3]; 3368 PetscInt numBlocks, numBlocksPlus; 3369 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; 3370 const PetscInt pattern[64][4] = { 3371 /* face to vertex within the coarse discretization of a single gyroid block */ 3372 /* layer 0 */ 3373 {A, C, K, G }, 3374 {C, B, II, K }, 3375 {D, A, H, L }, 3376 {B + 56 * 1, D, L, J }, 3377 {E, B + 56 * 1, J, N }, 3378 {A + 56 * 2, E, N, H + 56 * 2 }, 3379 {F, A + 56 * 2, G + 56 * 2, M }, 3380 {B, F, M, II }, 3381 /* layer 1 */ 3382 {G, K, Q, O }, 3383 {K, II, P, Q }, 3384 {L, H, O + 56 * 1, R }, 3385 {J, L, R, P }, 3386 {N, J, P, S }, 3387 {H + 56 * 2, N, S, O + 56 * 3 }, 3388 {M, G + 56 * 2, O + 56 * 2, T }, 3389 {II, M, T, P }, 3390 /* layer 2 */ 3391 {O, Q, Y, U }, 3392 {Q, P, W, Y }, 3393 {R, O + 56 * 1, U + 56 * 1, Ap }, 3394 {P, R, Ap, W }, 3395 {S, P, X, Bp }, 3396 {O + 56 * 3, S, Bp, V + 56 * 1 }, 3397 {T, O + 56 * 2, V, Z }, 3398 {P, T, Z, X }, 3399 /* layer 3 */ 3400 {U, Y, Ep, Dp }, 3401 {Y, W, Cp, Ep }, 3402 {Ap, U + 56 * 1, Dp + 56 * 1, Gp }, 3403 {W, Ap, Gp, Cp }, 3404 {Bp, X, Cp + 56 * 2, Fp }, 3405 {V + 56 * 1, Bp, Fp, Dp + 56 * 1}, 3406 {Z, V, Dp, Hp }, 3407 {X, Z, Hp, Cp + 56 * 2}, 3408 /* layer 4 */ 3409 {Dp, Ep, Mp, Kp }, 3410 {Ep, Cp, Ip, Mp }, 3411 {Gp, Dp + 56 * 1, Lp, Np }, 3412 {Cp, Gp, Np, Jp }, 3413 {Fp, Cp + 56 * 2, Jp + 56 * 2, Pp }, 3414 {Dp + 56 * 1, Fp, Pp, Lp }, 3415 {Hp, Dp, Kp, Op }, 3416 {Cp + 56 * 2, Hp, Op, Ip + 56 * 2}, 3417 /* layer 5 */ 3418 {Kp, Mp, Sp, Rp }, 3419 {Mp, Ip, Qp, Sp }, 3420 {Np, Lp, Rp, Tp }, 3421 {Jp, Np, Tp, Qp + 56 * 1}, 3422 {Pp, Jp + 56 * 2, Qp + 56 * 3, Up }, 3423 {Lp, Pp, Up, Rp }, 3424 {Op, Kp, Rp, Vp }, 3425 {Ip + 56 * 2, Op, Vp, Qp + 56 * 2}, 3426 /* layer 6 */ 3427 {Rp, Sp, Aq, Yp }, 3428 {Sp, Qp, Wp, Aq }, 3429 {Tp, Rp, Yp, Cq }, 3430 {Qp + 56 * 1, Tp, Cq, Wp + 56 * 1}, 3431 {Up, Qp + 56 * 3, Xp + 56 * 1, Dq }, 3432 {Rp, Up, Dq, Zp }, 3433 {Vp, Rp, Zp, Bq }, 3434 {Qp + 56 * 2, Vp, Bq, Xp }, 3435 /* layer 7 (the top is the periodic image of the bottom of layer 0) */ 3436 {Yp, Aq, C + 56 * 4, A + 56 * 4 }, 3437 {Aq, Wp, B + 56 * 4, C + 56 * 4 }, 3438 {Cq, Yp, A + 56 * 4, D + 56 * 4 }, 3439 {Wp + 56 * 1, Cq, D + 56 * 4, B + 56 * 5 }, 3440 {Dq, Xp + 56 * 1, B + 56 * 5, E + 56 * 4 }, 3441 {Zp, Dq, E + 56 * 4, A + 56 * 6 }, 3442 {Bq, Zp, A + 56 * 6, F + 56 * 4 }, 3443 {Xp, Bq, F + 56 * 4, B + 56 * 4 } 3444 }; 3445 const PetscReal gamma = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI; 3446 const PetscReal patternCoords[56][3] = { 3447 {1., 0., 0. }, /* A */ 3448 {0., 1., 0. }, /* B */ 3449 {gamma, gamma, 0. }, /* C */ 3450 {1 + gamma, 1 - gamma, 0. }, /* D */ 3451 {2 - gamma, 2 - gamma, 0. }, /* E */ 3452 {1 - gamma, 1 + gamma, 0. }, /* F */ 3453 3454 {.5, 0, .25 }, /* G */ 3455 {1.5, 0., .25 }, /* H */ 3456 {.5, 1., .25 }, /* II */ 3457 {1.5, 1., .25 }, /* J */ 3458 {.25, .5, .25 }, /* K */ 3459 {1.25, .5, .25 }, /* L */ 3460 {.75, 1.5, .25 }, /* M */ 3461 {1.75, 1.5, .25 }, /* N */ 3462 3463 {0., 0., .5 }, /* O */ 3464 {1., 1., .5 }, /* P */ 3465 {gamma, 1 - gamma, .5 }, /* Q */ 3466 {1 + gamma, gamma, .5 }, /* R */ 3467 {2 - gamma, 1 + gamma, .5 }, /* S */ 3468 {1 - gamma, 2 - gamma, .5 }, /* T */ 3469 3470 {0., .5, .75 }, /* U */ 3471 {0., 1.5, .75 }, /* V */ 3472 {1., .5, .75 }, /* W */ 3473 {1., 1.5, .75 }, /* X */ 3474 {.5, .75, .75 }, /* Y */ 3475 {.5, 1.75, .75 }, /* Z */ 3476 {1.5, .25, .75 }, /* Ap */ 3477 {1.5, 1.25, .75 }, /* Bp */ 3478 3479 {1., 0., 1. }, /* Cp */ 3480 {0., 1., 1. }, /* Dp */ 3481 {1 - gamma, 1 - gamma, 1. }, /* Ep */ 3482 {1 + gamma, 1 + gamma, 1. }, /* Fp */ 3483 {2 - gamma, gamma, 1. }, /* Gp */ 3484 {gamma, 2 - gamma, 1. }, /* Hp */ 3485 3486 {.5, 0., 1.25}, /* Ip */ 3487 {1.5, 0., 1.25}, /* Jp */ 3488 {.5, 1., 1.25}, /* Kp */ 3489 {1.5, 1., 1.25}, /* Lp */ 3490 {.75, .5, 1.25}, /* Mp */ 3491 {1.75, .5, 1.25}, /* Np */ 3492 {.25, 1.5, 1.25}, /* Op */ 3493 {1.25, 1.5, 1.25}, /* Pp */ 3494 3495 {0., 0., 1.5 }, /* Qp */ 3496 {1., 1., 1.5 }, /* Rp */ 3497 {1 - gamma, gamma, 1.5 }, /* Sp */ 3498 {2 - gamma, 1 - gamma, 1.5 }, /* Tp */ 3499 {1 + gamma, 2 - gamma, 1.5 }, /* Up */ 3500 {gamma, 1 + gamma, 1.5 }, /* Vp */ 3501 3502 {0., .5, 1.75}, /* Wp */ 3503 {0., 1.5, 1.75}, /* Xp */ 3504 {1., .5, 1.75}, /* Yp */ 3505 {1., 1.5, 1.75}, /* Zp */ 3506 {.5, .25, 1.75}, /* Aq */ 3507 {.5, 1.25, 1.75}, /* Bq */ 3508 {1.5, .75, 1.75}, /* Cq */ 3509 {1.5, 1.75, 1.75}, /* Dq */ 3510 }; 3511 PetscInt(*cells)[64][4] = NULL; 3512 PetscBool *seen; 3513 PetscInt *vertToTrueVert; 3514 PetscInt count; 3515 3516 for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1; 3517 numBlocks = 1; 3518 for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i]; 3519 numBlocksPlus = 1; 3520 for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i]; 3521 numFaces = numBlocks * facesPerBlock; 3522 PetscCall(PetscMalloc1(numBlocks, &cells)); 3523 PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen)); 3524 for (PetscInt k = 0; k < extent[2]; k++) { 3525 for (PetscInt j = 0; j < extent[1]; j++) { 3526 for (PetscInt i = 0; i < extent[0]; i++) { 3527 for (PetscInt f = 0; f < facesPerBlock; f++) { 3528 for (PetscInt v = 0; v < 4; v++) { 3529 PetscInt vertRaw = pattern[f][v]; 3530 PetscInt blockidx = vertRaw / 56; 3531 PetscInt patternvert = vertRaw % 56; 3532 PetscInt xplus = (blockidx & 1); 3533 PetscInt yplus = (blockidx & 2) >> 1; 3534 PetscInt zplus = (blockidx & 4) >> 2; 3535 PetscInt zcoord = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus); 3536 PetscInt ycoord = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus); 3537 PetscInt xcoord = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus); 3538 PetscInt vert = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert; 3539 3540 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert; 3541 seen[vert] = PETSC_TRUE; 3542 } 3543 } 3544 } 3545 } 3546 } 3547 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) 3548 if (seen[i]) numVertices++; 3549 count = 0; 3550 PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert)); 3551 PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords)); 3552 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1; 3553 for (PetscInt k = 0; k < extentPlus[2]; k++) { 3554 for (PetscInt j = 0; j < extentPlus[1]; j++) { 3555 for (PetscInt i = 0; i < extentPlus[0]; i++) { 3556 for (PetscInt v = 0; v < vertsPerBlock; v++) { 3557 PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v; 3558 3559 if (seen[vIdx]) { 3560 PetscInt thisVert; 3561 3562 vertToTrueVert[vIdx] = thisVert = count++; 3563 3564 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d]; 3565 vtxCoords[3 * thisVert + 0] += i * 2; 3566 vtxCoords[3 * thisVert + 1] += j * 2; 3567 vtxCoords[3 * thisVert + 2] += k * 2; 3568 } 3569 } 3570 } 3571 } 3572 } 3573 for (PetscInt i = 0; i < numBlocks; i++) { 3574 for (PetscInt f = 0; f < facesPerBlock; f++) { 3575 for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]]; 3576 } 3577 } 3578 PetscCall(PetscFree(vertToTrueVert)); 3579 PetscCall(PetscFree(seen)); 3580 cells_flat = cells[0][0]; 3581 numEdges = 0; 3582 for (PetscInt i = 0; i < numFaces; i++) { 3583 for (PetscInt e = 0; e < 4; e++) { 3584 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 3585 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 3586 3587 for (PetscInt d = 0; d < 3; d++) { 3588 if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) { 3589 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++; 3590 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++; 3591 } 3592 } 3593 } 3594 } 3595 PetscCall(PetscMalloc1(numEdges, &edges)); 3596 PetscCall(PetscMalloc1(numEdges, &edgeSets)); 3597 for (PetscInt edge = 0, i = 0; i < numFaces; i++) { 3598 for (PetscInt e = 0; e < 4; e++) { 3599 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 3600 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 3601 3602 for (PetscInt d = 0; d < 3; d++) { 3603 if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) { 3604 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) { 3605 edges[edge][0] = ev[0]; 3606 edges[edge][1] = ev[1]; 3607 edgeSets[edge++] = 2 * d; 3608 } 3609 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) { 3610 edges[edge][0] = ev[0]; 3611 edges[edge][1] = ev[1]; 3612 edgeSets[edge++] = 2 * d + 1; 3613 } 3614 } 3615 } 3616 } 3617 } 3618 } 3619 evalFunc = TPSEvaluate_Gyroid; 3620 normalFunc = TPSExtrudeNormalFunc_Gyroid; 3621 break; 3622 } 3623 3624 PetscCall(DMSetDimension(dm, topoDim)); 3625 if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat)); 3626 else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL)); 3627 PetscCall(PetscFree(cells_flat)); 3628 { 3629 DM idm; 3630 PetscCall(DMPlexInterpolate(dm, &idm)); 3631 PetscCall(DMPlexReplace_Internal(dm, &idm)); 3632 } 3633 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords)); 3634 else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL)); 3635 PetscCall(PetscFree(vtxCoords)); 3636 3637 PetscCall(DMCreateLabel(dm, "Face Sets")); 3638 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 3639 for (PetscInt e = 0; e < numEdges; e++) { 3640 PetscInt njoin; 3641 const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]}; 3642 PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join)); 3643 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]); 3644 PetscCall(DMLabelSetValue(label, join[0], edgeSets[e])); 3645 PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join)); 3646 } 3647 PetscCall(PetscFree(edges)); 3648 PetscCall(PetscFree(edgeSets)); 3649 if (tps_distribute) { 3650 DM pdm = NULL; 3651 PetscPartitioner part; 3652 3653 PetscCall(DMPlexGetPartitioner(dm, &part)); 3654 PetscCall(PetscPartitionerSetFromOptions(part)); 3655 PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm)); 3656 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 3657 // Do not auto-distribute again 3658 PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE)); 3659 } 3660 3661 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 3662 for (PetscInt refine = 0; refine < refinements; refine++) { 3663 PetscInt m; 3664 DM dmf; 3665 Vec X; 3666 PetscScalar *x; 3667 PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf)); 3668 PetscCall(DMPlexReplace_Internal(dm, &dmf)); 3669 3670 PetscCall(DMGetCoordinatesLocal(dm, &X)); 3671 PetscCall(VecGetLocalSize(X, &m)); 3672 PetscCall(VecGetArray(X, &x)); 3673 for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i])); 3674 PetscCall(VecRestoreArray(X, &x)); 3675 } 3676 3677 // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices. 3678 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 3679 PetscCall(DMPlexLabelComplete(dm, label)); 3680 3681 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 3682 3683 if (thickness > 0) { 3684 DM edm, cdm, ecdm; 3685 DMPlexTransform tr; 3686 const char *prefix; 3687 PetscOptions options; 3688 // Code from DMPlexExtrude 3689 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 3690 PetscCall(DMPlexTransformSetDM(tr, dm)); 3691 PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDE)); 3692 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 3693 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 3694 PetscCall(PetscObjectGetOptions((PetscObject)dm, &options)); 3695 PetscCall(PetscObjectSetOptions((PetscObject)tr, options)); 3696 PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers)); 3697 PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness)); 3698 PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE)); 3699 PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE)); 3700 PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc)); 3701 PetscCall(DMPlexTransformSetFromOptions(tr)); 3702 PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL)); 3703 PetscCall(DMPlexTransformSetUp(tr)); 3704 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view")); 3705 PetscCall(DMPlexTransformApply(tr, dm, &edm)); 3706 PetscCall(DMCopyDisc(dm, edm)); 3707 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3708 PetscCall(DMGetCoordinateDM(edm, &ecdm)); 3709 PetscCall(DMCopyDisc(cdm, ecdm)); 3710 PetscCall(DMPlexTransformCreateDiscLabels(tr, edm)); 3711 PetscCall(DMPlexTransformDestroy(&tr)); 3712 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, edm)); 3713 PetscCall(DMPlexReplace_Internal(dm, &edm)); 3714 } 3715 PetscFunctionReturn(PETSC_SUCCESS); 3716 } 3717 3718 /*@ 3719 DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface 3720 3721 Collective 3722 3723 Input Parameters: 3724 + comm - The communicator for the `DM` object 3725 . tpstype - Type of triply-periodic surface 3726 . extent - Array of length 3 containing number of periods in each direction 3727 . periodic - array of length 3 with periodicity, or `NULL` for non-periodic 3728 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable) 3729 . refinements - Number of factor-of-2 refinements of 2D manifold mesh 3730 . layers - Number of cell layers extruded in normal direction 3731 - thickness - Thickness in normal direction 3732 3733 Output Parameter: 3734 . dm - The `DM` object 3735 3736 Level: beginner 3737 3738 Notes: 3739 This meshes the surface of the Schwarz P or Gyroid surfaces. Schwarz P is the simplest member of the triply-periodic minimal surfaces. 3740 <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries. 3741 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. 3742 Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested. 3743 On each refinement, all vertices are projected to their nearest point on the surface. 3744 This projection could readily be extended to related surfaces. 3745 3746 See {cite}`maskery2018insights` 3747 3748 The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$. 3749 When the mesh is refined, "Face Sets" contain the new vertices (created during refinement). 3750 Use `DMPlexLabelComplete()` to propagate to coarse-level vertices. 3751 3752 Developer Notes: 3753 The Gyroid mesh does not currently mark boundary sets. 3754 3755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()` 3756 @*/ 3757 PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm) 3758 { 3759 PetscFunctionBegin; 3760 PetscCall(DMCreate(comm, dm)); 3761 PetscCall(DMSetType(*dm, DMPLEX)); 3762 PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness)); 3763 PetscFunctionReturn(PETSC_SUCCESS); 3764 } 3765 3766 /*@ 3767 DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d. 3768 3769 Collective 3770 3771 Input Parameters: 3772 + comm - The communicator for the `DM` object 3773 . dim - The dimension 3774 . simplex - Use simplices, or tensor product cells 3775 - R - The radius 3776 3777 Output Parameter: 3778 . dm - The `DM` object 3779 3780 Level: beginner 3781 3782 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 3783 @*/ 3784 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm) 3785 { 3786 PetscFunctionBegin; 3787 PetscAssertPointer(dm, 5); 3788 PetscCall(DMCreate(comm, dm)); 3789 PetscCall(DMSetType(*dm, DMPLEX)); 3790 PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R)); 3791 PetscFunctionReturn(PETSC_SUCCESS); 3792 } 3793 3794 static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R) 3795 { 3796 DM sdm, vol; 3797 DMLabel bdlabel; 3798 const char *prefix; 3799 3800 PetscFunctionBegin; 3801 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm)); 3802 PetscCall(DMSetType(sdm, DMPLEX)); 3803 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 3804 PetscCall(DMSetOptionsPrefix(sdm, prefix)); 3805 PetscCall(DMAppendOptionsPrefix(sdm, "bd_")); 3806 PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE)); 3807 PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R)); 3808 PetscCall(DMSetFromOptions(sdm)); 3809 PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view")); 3810 PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol)); 3811 PetscCall(DMDestroy(&sdm)); 3812 PetscCall(DMPlexReplace_Internal(dm, &vol)); 3813 PetscCall(DMCreateLabel(dm, "marker")); 3814 PetscCall(DMGetLabel(dm, "marker", &bdlabel)); 3815 PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel)); 3816 PetscCall(DMPlexLabelComplete(dm, bdlabel)); 3817 PetscFunctionReturn(PETSC_SUCCESS); 3818 } 3819 3820 /*@ 3821 DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d. 3822 3823 Collective 3824 3825 Input Parameters: 3826 + comm - The communicator for the `DM` object 3827 . dim - The dimension 3828 - R - The radius 3829 3830 Output Parameter: 3831 . dm - The `DM` object 3832 3833 Options Database Key: 3834 . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry 3835 3836 Level: beginner 3837 3838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 3839 @*/ 3840 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm) 3841 { 3842 PetscFunctionBegin; 3843 PetscCall(DMCreate(comm, dm)); 3844 PetscCall(DMSetType(*dm, DMPLEX)); 3845 PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R)); 3846 PetscFunctionReturn(PETSC_SUCCESS); 3847 } 3848 3849 static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct) 3850 { 3851 PetscFunctionBegin; 3852 switch (ct) { 3853 case DM_POLYTOPE_POINT: { 3854 PetscInt numPoints[1] = {1}; 3855 PetscInt coneSize[1] = {0}; 3856 PetscInt cones[1] = {0}; 3857 PetscInt coneOrientations[1] = {0}; 3858 PetscScalar vertexCoords[1] = {0.0}; 3859 3860 PetscCall(DMSetDimension(rdm, 0)); 3861 PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3862 } break; 3863 case DM_POLYTOPE_SEGMENT: { 3864 PetscInt numPoints[2] = {2, 1}; 3865 PetscInt coneSize[3] = {2, 0, 0}; 3866 PetscInt cones[2] = {1, 2}; 3867 PetscInt coneOrientations[2] = {0, 0}; 3868 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 3869 3870 PetscCall(DMSetDimension(rdm, 1)); 3871 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3872 } break; 3873 case DM_POLYTOPE_POINT_PRISM_TENSOR: { 3874 PetscInt numPoints[2] = {2, 1}; 3875 PetscInt coneSize[3] = {2, 0, 0}; 3876 PetscInt cones[2] = {1, 2}; 3877 PetscInt coneOrientations[2] = {0, 0}; 3878 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 3879 3880 PetscCall(DMSetDimension(rdm, 1)); 3881 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3882 } break; 3883 case DM_POLYTOPE_TRIANGLE: { 3884 PetscInt numPoints[2] = {3, 1}; 3885 PetscInt coneSize[4] = {3, 0, 0, 0}; 3886 PetscInt cones[3] = {1, 2, 3}; 3887 PetscInt coneOrientations[3] = {0, 0, 0}; 3888 PetscScalar vertexCoords[6] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0}; 3889 3890 PetscCall(DMSetDimension(rdm, 2)); 3891 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3892 } break; 3893 case DM_POLYTOPE_QUADRILATERAL: { 3894 PetscInt numPoints[2] = {4, 1}; 3895 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 3896 PetscInt cones[4] = {1, 2, 3, 4}; 3897 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 3898 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0}; 3899 3900 PetscCall(DMSetDimension(rdm, 2)); 3901 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3902 } break; 3903 case DM_POLYTOPE_SEG_PRISM_TENSOR: { 3904 PetscInt numPoints[2] = {4, 1}; 3905 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 3906 PetscInt cones[4] = {1, 2, 3, 4}; 3907 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 3908 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; 3909 3910 PetscCall(DMSetDimension(rdm, 2)); 3911 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3912 } break; 3913 case DM_POLYTOPE_TETRAHEDRON: { 3914 PetscInt numPoints[2] = {4, 1}; 3915 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 3916 PetscInt cones[4] = {1, 2, 3, 4}; 3917 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 3918 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}; 3919 3920 PetscCall(DMSetDimension(rdm, 3)); 3921 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3922 } break; 3923 case DM_POLYTOPE_HEXAHEDRON: { 3924 PetscInt numPoints[2] = {8, 1}; 3925 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 3926 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 3927 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 3928 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}; 3929 3930 PetscCall(DMSetDimension(rdm, 3)); 3931 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3932 } break; 3933 case DM_POLYTOPE_TRI_PRISM: { 3934 PetscInt numPoints[2] = {6, 1}; 3935 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 3936 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 3937 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 3938 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}; 3939 3940 PetscCall(DMSetDimension(rdm, 3)); 3941 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3942 } break; 3943 case DM_POLYTOPE_TRI_PRISM_TENSOR: { 3944 PetscInt numPoints[2] = {6, 1}; 3945 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 3946 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 3947 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 3948 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}; 3949 3950 PetscCall(DMSetDimension(rdm, 3)); 3951 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3952 } break; 3953 case DM_POLYTOPE_QUAD_PRISM_TENSOR: { 3954 PetscInt numPoints[2] = {8, 1}; 3955 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 3956 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 3957 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 3958 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}; 3959 3960 PetscCall(DMSetDimension(rdm, 3)); 3961 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3962 } break; 3963 case DM_POLYTOPE_PYRAMID: { 3964 PetscInt numPoints[2] = {5, 1}; 3965 PetscInt coneSize[6] = {5, 0, 0, 0, 0, 0}; 3966 PetscInt cones[5] = {1, 2, 3, 4, 5}; 3967 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 3968 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}; 3969 3970 PetscCall(DMSetDimension(rdm, 3)); 3971 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 3972 } break; 3973 default: 3974 SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]); 3975 } 3976 { 3977 PetscInt Nv, v; 3978 3979 /* Must create the celltype label here so that we do not automatically try to compute the types */ 3980 PetscCall(DMCreateLabel(rdm, "celltype")); 3981 PetscCall(DMPlexSetCellType(rdm, 0, ct)); 3982 PetscCall(DMPlexGetChart(rdm, NULL, &Nv)); 3983 for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT)); 3984 } 3985 PetscCall(DMPlexInterpolateInPlace_Internal(rdm)); 3986 PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct])); 3987 PetscFunctionReturn(PETSC_SUCCESS); 3988 } 3989 3990 /*@ 3991 DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell 3992 3993 Collective 3994 3995 Input Parameters: 3996 + comm - The communicator 3997 - ct - The cell type of the reference cell 3998 3999 Output Parameter: 4000 . refdm - The reference cell 4001 4002 Level: intermediate 4003 4004 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()` 4005 @*/ 4006 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm) 4007 { 4008 PetscFunctionBegin; 4009 PetscCall(DMCreate(comm, refdm)); 4010 PetscCall(DMSetType(*refdm, DMPLEX)); 4011 PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct)); 4012 PetscFunctionReturn(PETSC_SUCCESS); 4013 } 4014 4015 static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[]) 4016 { 4017 DM plex; 4018 DMLabel label; 4019 PetscBool hasLabel; 4020 4021 PetscFunctionBegin; 4022 PetscCall(DMHasLabel(dm, name, &hasLabel)); 4023 if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS); 4024 PetscCall(DMCreateLabel(dm, name)); 4025 PetscCall(DMGetLabel(dm, name, &label)); 4026 PetscCall(DMConvert(dm, DMPLEX, &plex)); 4027 PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label)); 4028 PetscCall(DMPlexLabelComplete(plex, label)); 4029 PetscCall(DMDestroy(&plex)); 4030 PetscFunctionReturn(PETSC_SUCCESS); 4031 } 4032 4033 /* 4034 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. 4035 4036 (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0])) 4037 */ 4038 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[]) 4039 { 4040 const PetscReal low = PetscRealPart(constants[0]); 4041 const PetscReal upp = PetscRealPart(constants[1]); 4042 const PetscReal r = PetscRealPart(u[1]); 4043 const PetscReal th = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low); 4044 4045 f0[0] = r * PetscCosReal(th); 4046 f0[1] = r * PetscSinReal(th); 4047 } 4048 4049 // Insert vertices and their joins, marked by depth 4050 static PetscErrorCode ProcessCohesiveLabel_Vertices(DM dm, DMLabel label, DMLabel vlabel, PetscInt val, PetscInt n, const PetscInt vertices[]) 4051 { 4052 PetscFunctionBegin; 4053 PetscCall(DMPlexMarkSubmesh_Interpolated(dm, vlabel, val, PETSC_FALSE, PETSC_FALSE, label, NULL)); 4054 PetscFunctionReturn(PETSC_SUCCESS); 4055 } 4056 4057 // Insert faces and their closures, marked by depth 4058 static PetscErrorCode ProcessCohesiveLabel_Faces(DM dm, DMLabel label, PetscInt n, const PetscInt faces[]) 4059 { 4060 PetscFunctionBegin; 4061 for (PetscInt p = 0; p < n; ++p) { 4062 const PetscInt point = faces[p]; 4063 PetscInt *closure = NULL; 4064 PetscInt clSize, pdepth; 4065 4066 PetscCall(DMPlexGetPointDepth(dm, point, &pdepth)); 4067 PetscCall(DMLabelSetValue(label, point, pdepth)); 4068 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4069 for (PetscInt cl = 0; cl < clSize * 2; cl += 2) { 4070 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth)); 4071 PetscCall(DMLabelSetValue(label, closure[cl], pdepth)); 4072 } 4073 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4074 } 4075 PetscFunctionReturn(PETSC_SUCCESS); 4076 } 4077 4078 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg); 4079 4080 const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL}; 4081 4082 static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems *PetscOptionsObject, PetscBool *useCoordSpace, DM dm) 4083 { 4084 DMPlexShape shape = DM_SHAPE_BOX; 4085 DMPolytopeType cell = DM_POLYTOPE_TRIANGLE; 4086 PetscInt dim = 2; 4087 PetscBool simplex = PETSC_TRUE, interpolate = PETSC_TRUE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE; 4088 PetscBool flg, flg2, fflg, strflg, bdfflg, nameflg; 4089 MPI_Comm comm; 4090 char filename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 4091 char bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 4092 char plexname[PETSC_MAX_PATH_LEN] = ""; 4093 const char *option; 4094 4095 PetscFunctionBegin; 4096 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 4097 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4098 /* TODO Turn this into a registration interface */ 4099 PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg)); 4100 PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg)); 4101 PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg)); 4102 PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg)); 4103 PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL)); 4104 PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL)); 4105 PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg)); 4106 PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0)); 4107 PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg)); 4108 PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg)); 4109 PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg)); 4110 PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2)); 4111 if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure)); 4112 4113 switch (cell) { 4114 case DM_POLYTOPE_POINT: 4115 case DM_POLYTOPE_SEGMENT: 4116 case DM_POLYTOPE_POINT_PRISM_TENSOR: 4117 case DM_POLYTOPE_TRIANGLE: 4118 case DM_POLYTOPE_QUADRILATERAL: 4119 case DM_POLYTOPE_TETRAHEDRON: 4120 case DM_POLYTOPE_HEXAHEDRON: 4121 *useCoordSpace = PETSC_TRUE; 4122 break; 4123 default: 4124 *useCoordSpace = PETSC_FALSE; 4125 break; 4126 } 4127 4128 if (fflg) { 4129 DM dmnew; 4130 const char *name; 4131 4132 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 4133 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, nameflg ? plexname : name, interpolate, &dmnew)); 4134 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4135 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4136 } else if (refDomain) { 4137 PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell)); 4138 } else if (bdfflg) { 4139 DM bdm, dmnew; 4140 const char *name; 4141 4142 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 4143 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, nameflg ? plexname : name, interpolate, &bdm)); 4144 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_")); 4145 PetscCall(DMSetFromOptions(bdm)); 4146 PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew)); 4147 PetscCall(DMDestroy(&bdm)); 4148 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4149 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4150 } else if (strflg) { 4151 DM dmnew; 4152 PetscViewer viewer; 4153 const char *contents; 4154 char *strname; 4155 char tmpdir[PETSC_MAX_PATH_LEN]; 4156 char tmpfilename[PETSC_MAX_PATH_LEN]; 4157 char name[PETSC_MAX_PATH_LEN]; 4158 MPI_Comm comm; 4159 PetscMPIInt rank; 4160 4161 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4162 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 4163 PetscCall(PetscStrchr(filename, ':', &strname)); 4164 PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename); 4165 strname[0] = '\0'; 4166 ++strname; 4167 PetscCall(PetscDLSym(NULL, strname, (void **)&contents)); 4168 PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname); 4169 PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN)); 4170 PetscCall(PetscStrlcat(tmpdir, "/meshXXXXXX", PETSC_MAX_PATH_LEN)); 4171 PetscCall(PetscMkdtemp(tmpdir)); 4172 PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh.%s", tmpdir, filename)); 4173 PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer)); 4174 PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents)); 4175 PetscCall(PetscViewerDestroy(&viewer)); 4176 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew)); 4177 PetscCall(PetscRMTree(tmpdir)); 4178 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname)); 4179 PetscCall(PetscObjectSetName((PetscObject)dm, name)); 4180 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4181 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4182 } else { 4183 PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape])); 4184 switch (shape) { 4185 case DM_SHAPE_BOX: 4186 case DM_SHAPE_ZBOX: 4187 case DM_SHAPE_ANNULUS: { 4188 PetscInt faces[3] = {0, 0, 0}; 4189 PetscReal lower[3] = {0, 0, 0}; 4190 PetscReal upper[3] = {1, 1, 1}; 4191 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4192 PetscBool isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE; 4193 PetscInt i, n; 4194 4195 n = dim; 4196 for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim); 4197 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4198 n = 3; 4199 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4200 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4201 n = 3; 4202 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4203 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4204 n = 3; 4205 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4206 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4207 4208 PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented"); 4209 if (isAnnular) 4210 for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC; 4211 4212 switch (cell) { 4213 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4214 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt)); 4215 if (!interpolate) { 4216 DM udm; 4217 4218 PetscCall(DMPlexUninterpolate(dm, &udm)); 4219 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4220 } 4221 break; 4222 default: 4223 PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate)); 4224 break; 4225 } 4226 if (isAnnular) { 4227 DM cdm; 4228 PetscDS cds; 4229 PetscScalar bounds[2] = {lower[0], upper[0]}; 4230 4231 // Fix coordinates for annular region 4232 PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 4233 PetscCall(DMSetCellCoordinatesLocal(dm, NULL)); 4234 PetscCall(DMSetCellCoordinates(dm, NULL)); 4235 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 4236 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4237 PetscCall(DMGetDS(cdm, &cds)); 4238 PetscCall(PetscDSSetConstants(cds, 2, bounds)); 4239 PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus)); 4240 } 4241 } break; 4242 case DM_SHAPE_BOX_SURFACE: { 4243 PetscInt faces[3] = {0, 0, 0}; 4244 PetscReal lower[3] = {0, 0, 0}; 4245 PetscReal upper[3] = {1, 1, 1}; 4246 PetscInt i, n; 4247 4248 n = dim + 1; 4249 for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1)); 4250 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4251 n = 3; 4252 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4253 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); 4254 n = 3; 4255 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4256 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); 4257 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate)); 4258 } break; 4259 case DM_SHAPE_SPHERE: { 4260 PetscReal R = 1.0; 4261 4262 PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg)); 4263 PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R)); 4264 } break; 4265 case DM_SHAPE_BALL: { 4266 PetscReal R = 1.0; 4267 4268 PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg)); 4269 PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R)); 4270 } break; 4271 case DM_SHAPE_CYLINDER: { 4272 DMBoundaryType bdt = DM_BOUNDARY_NONE; 4273 PetscInt Nw = 6; 4274 PetscInt Nr = 0; 4275 4276 PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL)); 4277 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL)); 4278 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_refine", "Number of refinements before projection", "", Nr, &Nr, NULL)); 4279 switch (cell) { 4280 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4281 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate)); 4282 break; 4283 default: 4284 PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt, Nr)); 4285 break; 4286 } 4287 } break; 4288 case DM_SHAPE_SCHWARZ_P: // fallthrough 4289 case DM_SHAPE_GYROID: { 4290 PetscInt extent[3] = {1, 1, 1}, refine = 0, layers = 0, three; 4291 PetscReal thickness = 0.; 4292 DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4293 DMPlexTPSType tps_type = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID; 4294 PetscBool tps_distribute; 4295 PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL)); 4296 PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL)); 4297 PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL)); 4298 PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL)); 4299 PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL)); 4300 PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute)); 4301 PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL)); 4302 PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness)); 4303 } break; 4304 case DM_SHAPE_DOUBLET: { 4305 DM dmnew; 4306 PetscReal rl = 0.0; 4307 4308 PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL)); 4309 PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew)); 4310 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4311 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4312 } break; 4313 case DM_SHAPE_HYPERCUBIC: { 4314 PetscInt *edges; 4315 PetscReal *lower, *upper; 4316 DMBoundaryType *bdt; 4317 PetscInt n, d; 4318 4319 *useCoordSpace = PETSC_FALSE; 4320 PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt)); 4321 for (d = 0; d < dim; ++d) { 4322 edges[d] = 1; 4323 lower[d] = 0.; 4324 upper[d] = 1.; 4325 bdt[d] = DM_BOUNDARY_PERIODIC; 4326 } 4327 n = dim; 4328 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg)); 4329 n = dim; 4330 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4331 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4332 n = dim; 4333 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4334 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4335 n = dim; 4336 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4337 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4338 PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt)); 4339 PetscCall(PetscFree4(edges, lower, upper, bdt)); 4340 } break; 4341 default: 4342 SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]); 4343 } 4344 } 4345 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4346 if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname)); 4347 // Allow label creation 4348 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg)); 4349 if (flg) { 4350 DMLabel label; 4351 PetscInt points[1024], n = 1024; 4352 char fulloption[PETSC_MAX_PATH_LEN]; 4353 const char *name = &option[14]; 4354 4355 PetscCall(DMCreateLabel(dm, name)); 4356 PetscCall(DMGetLabel(dm, name, &label)); 4357 fulloption[0] = '-'; 4358 fulloption[1] = 0; 4359 PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN)); 4360 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL)); 4361 for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1)); 4362 } 4363 // Allow cohesive label creation 4364 // Faces are input, completed, and all points are marked with their depth 4365 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg)); 4366 if (flg) { 4367 DMLabel label; 4368 PetscInt points[1024], n, pStart, pEnd, Nl = 1; 4369 PetscBool noCreate = PETSC_FALSE; 4370 char fulloption[PETSC_MAX_PATH_LEN]; 4371 char name[PETSC_MAX_PATH_LEN]; 4372 size_t len; 4373 4374 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4375 PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN)); 4376 PetscCall(PetscStrlen(name, &len)); 4377 if (name[len - 1] == '0') Nl = 10; 4378 for (PetscInt l = 0; l < Nl; ++l) { 4379 if (l > 0) name[len - 1] = (char)('0' + l); 4380 fulloption[0] = 0; 4381 PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32)); 4382 PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32)); 4383 n = 1024; 4384 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg)); 4385 if (!flg) break; 4386 PetscCall(DMHasLabel(dm, name, &noCreate)); 4387 if (noCreate) { 4388 DMLabel inlabel; 4389 IS pointIS; 4390 const PetscInt *lpoints; 4391 PetscInt pdep, ln, inval = points[0]; 4392 char newname[PETSC_MAX_PATH_LEN]; 4393 4394 PetscCheck(n == 1, comm, PETSC_ERR_ARG_WRONG, "Must specify a label value with this option"); 4395 PetscCall(DMGetLabel(dm, name, &inlabel)); 4396 PetscCall(DMLabelGetStratumIS(inlabel, inval, &pointIS)); 4397 PetscCall(ISGetLocalSize(pointIS, &ln)); 4398 PetscCall(ISGetIndices(pointIS, &lpoints)); 4399 PetscCall(DMPlexGetPointDepth(dm, lpoints[0], &pdep)); 4400 PetscCall(PetscSNPrintf(newname, PETSC_MAX_PATH_LEN, "%s%" PetscInt_FMT, name, points[0])); 4401 PetscCall(DMCreateLabel(dm, newname)); 4402 PetscCall(DMGetLabel(dm, newname, &label)); 4403 if (!pdep) PetscCall(ProcessCohesiveLabel_Vertices(dm, label, inlabel, inval, ln, lpoints)); 4404 else PetscCall(ProcessCohesiveLabel_Faces(dm, label, ln, lpoints)); 4405 PetscCall(ISRestoreIndices(pointIS, &lpoints)); 4406 PetscCall(ISDestroy(&pointIS)); 4407 } else { 4408 PetscCall(DMCreateLabel(dm, name)); 4409 PetscCall(DMGetLabel(dm, name, &label)); 4410 if (pStart >= pEnd) n = 0; 4411 PetscCall(ProcessCohesiveLabel_Faces(dm, label, n, points)); 4412 } 4413 PetscCall(DMPlexOrientLabel(dm, label)); 4414 PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL)); 4415 } 4416 } 4417 PetscCall(DMViewFromOptions(dm, NULL, "-created_dm_view")); 4418 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 4419 PetscFunctionReturn(PETSC_SUCCESS); 4420 } 4421 4422 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4423 { 4424 DM_Plex *mesh = (DM_Plex *)dm->data; 4425 PetscBool flg, flg2; 4426 char bdLabel[PETSC_MAX_PATH_LEN]; 4427 char method[PETSC_MAX_PATH_LEN]; 4428 4429 PetscFunctionBegin; 4430 /* Handle viewing */ 4431 PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL)); 4432 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0)); 4433 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0)); 4434 PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL)); 4435 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0)); 4436 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0)); 4437 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_project", "Debug output level all projection computations", "DMPlexProject", 0, &mesh->printProject, NULL, 0)); 4438 PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg)); 4439 if (flg) PetscCall(PetscLogDefaultBegin()); 4440 /* Labeling */ 4441 PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg)); 4442 if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel)); 4443 /* Point Location */ 4444 PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL)); 4445 /* Partitioning and distribution */ 4446 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL)); 4447 /* Reordering */ 4448 PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg)); 4449 if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE)); 4450 PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg)); 4451 if (flg) PetscCall(DMReorderSectionSetType(dm, method)); 4452 /* Generation and remeshing */ 4453 PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL)); 4454 /* Projection behavior */ 4455 PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0)); 4456 PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL)); 4457 /* Checking structure */ 4458 { 4459 PetscBool all = PETSC_FALSE; 4460 4461 PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL)); 4462 if (all) { 4463 PetscCall(DMPlexCheck(dm)); 4464 } else { 4465 PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2)); 4466 if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm)); 4467 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)); 4468 if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0)); 4469 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)); 4470 if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0)); 4471 PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2)); 4472 if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm)); 4473 PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2)); 4474 if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 4475 PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2)); 4476 if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm)); 4477 } 4478 PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2)); 4479 if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE)); 4480 } 4481 { 4482 PetscReal scale = 1.0; 4483 4484 PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg)); 4485 if (flg) { 4486 Vec coordinates, coordinatesLocal; 4487 4488 PetscCall(DMGetCoordinates(dm, &coordinates)); 4489 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 4490 PetscCall(VecScale(coordinates, scale)); 4491 PetscCall(VecScale(coordinatesLocal, scale)); 4492 } 4493 } 4494 PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner)); 4495 PetscFunctionReturn(PETSC_SUCCESS); 4496 } 4497 4498 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap) 4499 { 4500 PetscInt numOvLabels = 16, numOvExLabels = 16; 4501 char *ovLabelNames[16], *ovExLabelNames[16]; 4502 PetscInt numOvValues = 16, numOvExValues = 16, l; 4503 PetscBool flg; 4504 4505 PetscFunctionBegin; 4506 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0)); 4507 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg)); 4508 if (!flg) numOvLabels = 0; 4509 if (numOvLabels) { 4510 ((DM_Plex *)dm->data)->numOvLabels = numOvLabels; 4511 for (l = 0; l < numOvLabels; ++l) { 4512 PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l])); 4513 PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]); 4514 PetscCall(PetscFree(ovLabelNames[l])); 4515 } 4516 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg)); 4517 if (!flg) numOvValues = 0; 4518 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); 4519 4520 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg)); 4521 if (!flg) numOvExLabels = 0; 4522 ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels; 4523 for (l = 0; l < numOvExLabels; ++l) { 4524 PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l])); 4525 PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]); 4526 PetscCall(PetscFree(ovExLabelNames[l])); 4527 } 4528 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg)); 4529 if (!flg) numOvExValues = 0; 4530 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); 4531 } 4532 PetscFunctionReturn(PETSC_SUCCESS); 4533 } 4534 4535 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject) 4536 { 4537 PetscFunctionList ordlist; 4538 char oname[256]; 4539 char sublabelname[PETSC_MAX_PATH_LEN] = ""; 4540 DMReorderDefaultFlag reorder; 4541 PetscReal volume = -1.0; 4542 PetscInt prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim; 4543 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; 4544 4545 PetscFunctionBegin; 4546 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options"); 4547 if (dm->cloneOpts) goto non_refine; 4548 /* Handle automatic creation */ 4549 PetscCall(DMGetDimension(dm, &dim)); 4550 if (dim < 0) { 4551 PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm)); 4552 created = PETSC_TRUE; 4553 } 4554 PetscCall(DMGetDimension(dm, &dim)); 4555 /* Handle interpolation before distribution */ 4556 PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg)); 4557 if (flg) { 4558 DMPlexInterpolatedFlag interpolated; 4559 4560 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 4561 if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) { 4562 DM udm; 4563 4564 PetscCall(DMPlexUninterpolate(dm, &udm)); 4565 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4566 } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) { 4567 DM idm; 4568 4569 PetscCall(DMPlexInterpolate(dm, &idm)); 4570 PetscCall(DMPlexReplace_Internal(dm, &idm)); 4571 } 4572 } 4573 // Handle submesh selection before distribution 4574 PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg)); 4575 if (flg) { 4576 DM subdm; 4577 DMLabel label; 4578 IS valueIS, pointIS; 4579 const PetscInt *values, *points; 4580 PetscBool markedFaces = PETSC_FALSE; 4581 PetscInt Nv, value, Np; 4582 4583 PetscCall(DMGetLabel(dm, sublabelname, &label)); 4584 PetscCall(DMLabelGetNumValues(label, &Nv)); 4585 PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv); 4586 PetscCall(DMLabelGetValueIS(label, &valueIS)); 4587 PetscCall(ISGetIndices(valueIS, &values)); 4588 value = values[0]; 4589 PetscCall(ISRestoreIndices(valueIS, &values)); 4590 PetscCall(ISDestroy(&valueIS)); 4591 PetscCall(DMLabelGetStratumSize(label, value, &Np)); 4592 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 4593 PetscCall(ISGetIndices(pointIS, &points)); 4594 for (PetscInt p = 0; p < Np; ++p) { 4595 PetscInt pdepth; 4596 4597 PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth)); 4598 if (pdepth) { 4599 markedFaces = PETSC_TRUE; 4600 break; 4601 } 4602 } 4603 PetscCall(ISRestoreIndices(pointIS, &points)); 4604 PetscCall(ISDestroy(&pointIS)); 4605 PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm)); 4606 PetscCall(DMPlexReplace_Internal(dm, &subdm)); 4607 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4608 } 4609 /* Handle DMPlex refinement before distribution */ 4610 PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig)); 4611 PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0)); 4612 PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4613 PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg)); 4614 if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform)); 4615 PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg)); 4616 if (flg) { 4617 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE)); 4618 PetscCall(DMPlexSetRefinementLimit(dm, volume)); 4619 prerefine = PetscMax(prerefine, 1); 4620 } 4621 if (prerefine) PetscCall(DMLocalizeCoordinates(dm)); 4622 for (r = 0; r < prerefine; ++r) { 4623 DM rdm; 4624 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4625 4626 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4627 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4628 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4629 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4630 if (coordFunc && remap) { 4631 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4632 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4633 } 4634 } 4635 PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig)); 4636 /* Handle DMPlex extrusion before distribution */ 4637 PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0)); 4638 if (extLayers) { 4639 DM edm; 4640 4641 PetscCall(DMExtrude(dm, extLayers, &edm)); 4642 PetscCall(DMPlexReplace_Internal(dm, &edm)); 4643 ((DM_Plex *)dm->data)->coordFunc = NULL; 4644 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4645 extLayers = 0; 4646 PetscCall(DMGetDimension(dm, &dim)); 4647 } 4648 /* Handle DMPlex reordering before distribution */ 4649 PetscCall(DMPlexReorderGetDefault(dm, &reorder)); 4650 PetscCall(MatGetOrderingList(&ordlist)); 4651 PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname))); 4652 PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg)); 4653 if (reorder == DM_REORDER_DEFAULT_TRUE || flg) { 4654 DM pdm; 4655 IS perm; 4656 4657 PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm)); 4658 PetscCall(DMPlexPermute(dm, perm, &pdm)); 4659 PetscCall(ISDestroy(&perm)); 4660 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4661 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4662 } 4663 /* Handle DMPlex distribution */ 4664 PetscCall(DMPlexDistributeGetDefault(dm, &distribute)); 4665 PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL)); 4666 PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL)); 4667 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 4668 if (distribute) { 4669 DM pdm = NULL; 4670 PetscPartitioner part; 4671 PetscSF sfMigration; 4672 4673 PetscCall(DMPlexGetPartitioner(dm, &part)); 4674 PetscCall(PetscPartitionerSetFromOptions(part)); 4675 PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm)); 4676 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4677 if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration)); 4678 PetscCall(PetscSFDestroy(&sfMigration)); 4679 } 4680 4681 { 4682 PetscBool useBoxLabel = PETSC_FALSE; 4683 PetscCall(PetscOptionsBool("-dm_plex_box_label", "Create 'Face Sets' assuming boundary faces align with cartesian directions", "DMCreate", useBoxLabel, &useBoxLabel, NULL)); 4684 if (useBoxLabel) PetscCall(DMPlexSetBoxLabel_Internal(dm)); 4685 } 4686 /* Must check CEED options before creating function space for coordinates */ 4687 { 4688 PetscBool useCeed = PETSC_FALSE, flg; 4689 4690 PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg)); 4691 if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed)); 4692 } 4693 /* Create coordinate space */ 4694 if (created) { 4695 DM_Plex *mesh = (DM_Plex *)dm->data; 4696 PetscInt degree = 1, deg; 4697 PetscInt height = 0; 4698 DM cdm; 4699 PetscBool flg, localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE; 4700 4701 PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg)); 4702 PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, °ree, NULL)); 4703 PetscCall(DMGetCoordinateDegree_Internal(dm, °)); 4704 if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, mesh->coordFunc)); 4705 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4706 if (flg && !coordSpace) { 4707 PetscDS cds; 4708 PetscObject obj; 4709 PetscClassId id; 4710 4711 PetscCall(DMGetDS(cdm, &cds)); 4712 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4713 PetscCall(PetscObjectGetClassId(obj, &id)); 4714 if (id == PETSCFE_CLASSID) { 4715 PetscContainer dummy; 4716 4717 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy)); 4718 PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates")); 4719 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy)); 4720 PetscCall(PetscContainerDestroy(&dummy)); 4721 PetscCall(DMClearDS(cdm)); 4722 } 4723 mesh->coordFunc = NULL; 4724 } 4725 PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL)); 4726 PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg)); 4727 if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize)); 4728 PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg)); 4729 if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height)); 4730 if (localize) PetscCall(DMLocalizeCoordinates(dm)); 4731 } 4732 /* Handle DMPlex refinement */ 4733 remap = PETSC_TRUE; 4734 PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0)); 4735 PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 4736 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0)); 4737 if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4738 if (refine && isHierarchy) { 4739 DM *dms, coarseDM; 4740 4741 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 4742 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 4743 PetscCall(PetscMalloc1(refine, &dms)); 4744 PetscCall(DMRefineHierarchy(dm, refine, dms)); 4745 /* Total hack since we do not pass in a pointer */ 4746 PetscCall(DMPlexSwap_Static(dm, dms[refine - 1])); 4747 if (refine == 1) { 4748 PetscCall(DMSetCoarseDM(dm, dms[0])); 4749 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4750 } else { 4751 PetscCall(DMSetCoarseDM(dm, dms[refine - 2])); 4752 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 4753 PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1])); 4754 PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE)); 4755 } 4756 PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM)); 4757 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 4758 /* Free DMs */ 4759 for (r = 0; r < refine; ++r) { 4760 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4761 PetscCall(DMDestroy(&dms[r])); 4762 } 4763 PetscCall(PetscFree(dms)); 4764 } else { 4765 for (r = 0; r < refine; ++r) { 4766 DM rdm; 4767 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4768 4769 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4770 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 4771 /* Total hack since we do not pass in a pointer */ 4772 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4773 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4774 if (coordFunc && remap) { 4775 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4776 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4777 } 4778 } 4779 } 4780 /* Handle DMPlex coarsening */ 4781 PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0)); 4782 PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0)); 4783 if (coarsen && isHierarchy) { 4784 DM *dms; 4785 4786 PetscCall(PetscMalloc1(coarsen, &dms)); 4787 PetscCall(DMCoarsenHierarchy(dm, coarsen, dms)); 4788 /* Free DMs */ 4789 for (r = 0; r < coarsen; ++r) { 4790 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 4791 PetscCall(DMDestroy(&dms[r])); 4792 } 4793 PetscCall(PetscFree(dms)); 4794 } else { 4795 for (r = 0; r < coarsen; ++r) { 4796 DM cdm; 4797 PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc; 4798 4799 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4800 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm)); 4801 /* Total hack since we do not pass in a pointer */ 4802 PetscCall(DMPlexReplace_Internal(dm, &cdm)); 4803 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4804 if (coordFunc) { 4805 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 4806 ((DM_Plex *)dm->data)->coordFunc = coordFunc; 4807 } 4808 } 4809 } 4810 // Handle coordinate remapping 4811 remap = PETSC_FALSE; 4812 PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL)); 4813 if (remap) { 4814 DMPlexCoordMap map = DM_COORD_MAP_NONE; 4815 PetscPointFunc mapFunc = NULL; 4816 PetscScalar params[16]; 4817 PetscInt Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim; 4818 MPI_Comm comm; 4819 4820 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4821 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4822 PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg)); 4823 if (!flg) Np = 0; 4824 // TODO Allow user to pass a map function by name 4825 PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg)); 4826 if (flg) { 4827 switch (map) { 4828 case DM_COORD_MAP_NONE: 4829 mapFunc = coordMap_identity; 4830 break; 4831 case DM_COORD_MAP_SHEAR: 4832 mapFunc = coordMap_shear; 4833 if (!Np) { 4834 Np = cdim + 1; 4835 params[0] = 0; 4836 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 4837 } 4838 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); 4839 break; 4840 case DM_COORD_MAP_FLARE: 4841 mapFunc = coordMap_flare; 4842 if (!Np) { 4843 Np = cdim + 1; 4844 params[0] = 0; 4845 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 4846 } 4847 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); 4848 break; 4849 case DM_COORD_MAP_ANNULUS: 4850 mapFunc = coordMap_annulus; 4851 if (!Np) { 4852 Np = 2; 4853 params[0] = 1.; 4854 params[1] = 2.; 4855 } 4856 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 4857 break; 4858 case DM_COORD_MAP_SHELL: 4859 mapFunc = coordMap_shell; 4860 if (!Np) { 4861 Np = 2; 4862 params[0] = 1.; 4863 params[1] = 2.; 4864 } 4865 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 4866 break; 4867 default: 4868 mapFunc = coordMap_identity; 4869 } 4870 } 4871 if (Np) { 4872 DM cdm; 4873 PetscDS cds; 4874 4875 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4876 PetscCall(DMGetDS(cdm, &cds)); 4877 PetscCall(PetscDSSetConstants(cds, Np, params)); 4878 } 4879 PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc)); 4880 } 4881 /* Handle ghost cells */ 4882 PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL)); 4883 if (ghostCells) { 4884 DM gdm; 4885 char lname[PETSC_MAX_PATH_LEN]; 4886 4887 lname[0] = '\0'; 4888 PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg)); 4889 PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm)); 4890 PetscCall(DMPlexReplace_Internal(dm, &gdm)); 4891 } 4892 /* Handle 1D order */ 4893 if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) { 4894 DM cdm, rdm; 4895 PetscDS cds; 4896 PetscObject obj; 4897 PetscClassId id = PETSC_OBJECT_CLASSID; 4898 IS perm; 4899 PetscInt Nf; 4900 PetscBool distributed; 4901 4902 PetscCall(DMPlexIsDistributed(dm, &distributed)); 4903 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4904 PetscCall(DMGetDS(cdm, &cds)); 4905 PetscCall(PetscDSGetNumFields(cds, &Nf)); 4906 if (Nf) { 4907 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 4908 PetscCall(PetscObjectGetClassId(obj, &id)); 4909 } 4910 if (!distributed && id != PETSCFE_CLASSID) { 4911 PetscCall(DMPlexGetOrdering1D(dm, &perm)); 4912 PetscCall(DMPlexPermute(dm, perm, &rdm)); 4913 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 4914 PetscCall(ISDestroy(&perm)); 4915 } 4916 } 4917 /* Handle */ 4918 non_refine: 4919 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 4920 char *phases[16]; 4921 PetscInt Nphases = 16; 4922 PetscCall(PetscOptionsStringArray("-dm_plex_option_phases", "Option phase prefixes", "DMSetFromOptions", phases, &Nphases, &flg)); 4923 PetscOptionsHeadEnd(); 4924 4925 // Phases 4926 if (flg) { 4927 const char *oldPrefix; 4928 4929 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &oldPrefix)); 4930 for (PetscInt ph = 0; ph < Nphases; ++ph) { 4931 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, phases[ph])); 4932 PetscCall(PetscInfo(dm, "Options phase %s for DM %s\n", phases[ph], dm->hdr.name)); 4933 PetscCall(DMSetFromOptions(dm)); 4934 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix)); 4935 PetscCall(PetscFree(phases[ph])); 4936 } 4937 } 4938 PetscFunctionReturn(PETSC_SUCCESS); 4939 } 4940 4941 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec) 4942 { 4943 PetscFunctionBegin; 4944 PetscCall(DMCreateGlobalVector_Section_Private(dm, vec)); 4945 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 4946 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex)); 4947 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native)); 4948 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex)); 4949 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native)); 4950 PetscFunctionReturn(PETSC_SUCCESS); 4951 } 4952 4953 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec) 4954 { 4955 PetscFunctionBegin; 4956 PetscCall(DMCreateLocalVector_Section_Private(dm, vec)); 4957 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local)); 4958 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local)); 4959 PetscFunctionReturn(PETSC_SUCCESS); 4960 } 4961 4962 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 4963 { 4964 PetscInt depth, d; 4965 4966 PetscFunctionBegin; 4967 PetscCall(DMPlexGetDepth(dm, &depth)); 4968 if (depth == 1) { 4969 PetscCall(DMGetDimension(dm, &d)); 4970 if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4971 else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd)); 4972 else { 4973 *pStart = 0; 4974 *pEnd = 0; 4975 } 4976 } else { 4977 PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 4978 } 4979 PetscFunctionReturn(PETSC_SUCCESS); 4980 } 4981 4982 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 4983 { 4984 PetscSF sf; 4985 PetscMPIInt niranks, njranks; 4986 PetscInt n; 4987 const PetscMPIInt *iranks, *jranks; 4988 DM_Plex *data = (DM_Plex *)dm->data; 4989 4990 PetscFunctionBegin; 4991 PetscCall(DMGetPointSF(dm, &sf)); 4992 if (!data->neighbors) { 4993 PetscCall(PetscSFSetUp(sf)); 4994 PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL)); 4995 PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL)); 4996 PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors)); 4997 PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks)); 4998 PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks)); 4999 n = njranks + niranks; 5000 PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1)); 5001 /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */ 5002 PetscCall(PetscMPIIntCast(n, data->neighbors)); 5003 } 5004 if (nranks) *nranks = data->neighbors[0]; 5005 if (ranks) { 5006 if (data->neighbors[0]) *ranks = data->neighbors + 1; 5007 else *ranks = NULL; 5008 } 5009 PetscFunctionReturn(PETSC_SUCCESS); 5010 } 5011 5012 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec); 5013 5014 static PetscErrorCode DMInitialize_Plex(DM dm) 5015 { 5016 PetscFunctionBegin; 5017 dm->ops->view = DMView_Plex; 5018 dm->ops->load = DMLoad_Plex; 5019 dm->ops->setfromoptions = DMSetFromOptions_Plex; 5020 dm->ops->clone = DMClone_Plex; 5021 dm->ops->setup = DMSetUp_Plex; 5022 dm->ops->createlocalsection = DMCreateLocalSection_Plex; 5023 dm->ops->createsectionpermutation = DMCreateSectionPermutation_Plex; 5024 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_Plex; 5025 dm->ops->createglobalvector = DMCreateGlobalVector_Plex; 5026 dm->ops->createlocalvector = DMCreateLocalVector_Plex; 5027 dm->ops->getlocaltoglobalmapping = NULL; 5028 dm->ops->createfieldis = NULL; 5029 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Plex; 5030 dm->ops->createcoordinatefield = DMCreateCoordinateField_Plex; 5031 dm->ops->getcoloring = NULL; 5032 dm->ops->creatematrix = DMCreateMatrix_Plex; 5033 dm->ops->createinterpolation = DMCreateInterpolation_Plex; 5034 dm->ops->createmassmatrix = DMCreateMassMatrix_Plex; 5035 dm->ops->createmassmatrixlumped = DMCreateMassMatrixLumped_Plex; 5036 dm->ops->createinjection = DMCreateInjection_Plex; 5037 dm->ops->refine = DMRefine_Plex; 5038 dm->ops->coarsen = DMCoarsen_Plex; 5039 dm->ops->refinehierarchy = DMRefineHierarchy_Plex; 5040 dm->ops->coarsenhierarchy = DMCoarsenHierarchy_Plex; 5041 dm->ops->extrude = DMExtrude_Plex; 5042 dm->ops->globaltolocalbegin = NULL; 5043 dm->ops->globaltolocalend = NULL; 5044 dm->ops->localtoglobalbegin = NULL; 5045 dm->ops->localtoglobalend = NULL; 5046 dm->ops->destroy = DMDestroy_Plex; 5047 dm->ops->createsubdm = DMCreateSubDM_Plex; 5048 dm->ops->createsuperdm = DMCreateSuperDM_Plex; 5049 dm->ops->getdimpoints = DMGetDimPoints_Plex; 5050 dm->ops->locatepoints = DMLocatePoints_Plex; 5051 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_Plex; 5052 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex; 5053 dm->ops->projectfieldlocal = DMProjectFieldLocal_Plex; 5054 dm->ops->projectfieldlabellocal = DMProjectFieldLabelLocal_Plex; 5055 dm->ops->projectbdfieldlabellocal = DMProjectBdFieldLabelLocal_Plex; 5056 dm->ops->computel2diff = DMComputeL2Diff_Plex; 5057 dm->ops->computel2gradientdiff = DMComputeL2GradientDiff_Plex; 5058 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_Plex; 5059 dm->ops->getneighbors = DMGetNeighbors_Plex; 5060 dm->ops->getlocalboundingbox = DMGetLocalBoundingBox_Coordinates; 5061 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex; 5062 dm->ops->createddscatters = DMCreateDomainDecompositionScatters_Plex; 5063 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex)); 5064 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex)); 5065 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex)); 5066 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex)); 5067 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex)); 5068 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex)); 5069 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex)); 5070 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex)); 5071 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex)); 5072 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex)); 5073 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex)); 5074 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex)); 5075 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex)); 5076 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 5077 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex)); 5078 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex)); 5079 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex)); 5080 PetscFunctionReturn(PETSC_SUCCESS); 5081 } 5082 5083 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm) 5084 { 5085 DM_Plex *mesh = (DM_Plex *)dm->data; 5086 const PetscSF *face_sfs; 5087 PetscInt num_face_sfs; 5088 5089 PetscFunctionBegin; 5090 mesh->refct++; 5091 (*newdm)->data = mesh; 5092 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs)); 5093 PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs)); 5094 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX)); 5095 PetscCall(DMInitialize_Plex(*newdm)); 5096 PetscFunctionReturn(PETSC_SUCCESS); 5097 } 5098 5099 /*MC 5100 DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram. 5101 In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is 5102 specified by a PetscSection object. Ownership in the global representation is determined by 5103 ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object. 5104 5105 Options Database Keys: 5106 + -dm_refine_pre - Refine mesh before distribution 5107 + -dm_refine_uniform_pre - Choose uniform or generator-based refinement 5108 + -dm_refine_volume_limit_pre - Cell volume limit after pre-refinement using generator 5109 . -dm_distribute - Distribute mesh across processes 5110 . -dm_distribute_overlap - Number of cells to overlap for distribution 5111 . -dm_refine - Refine mesh after distribution 5112 . -dm_localize <bool> - Whether to localize coordinates for periodic meshes 5113 . -dm_sparse_localize <bool> - Whether to only localize cells on the periodic boundary 5114 . -dm_plex_hash_location - Use grid hashing for point location 5115 . -dm_plex_hash_box_faces <n,m,p> - The number of divisions in each direction of the grid hash 5116 . -dm_plex_partition_balance - Attempt to evenly divide points on partition boundary between processes 5117 . -dm_plex_remesh_bd - Allow changes to the boundary on remeshing 5118 . -dm_plex_max_projection_height - Maximum mesh point height used to project locally 5119 . -dm_plex_regular_refinement - Use special nested projection algorithm for regular refinement 5120 . -dm_plex_reorder_section - Use specialized blocking if available 5121 . -dm_plex_check_all - Perform all checks below 5122 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric 5123 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices 5124 . -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 5125 . -dm_plex_check_geometry - Check that cells have positive volume 5126 . -dm_view :mesh.tex:ascii_latex - View the mesh in LaTeX/TikZ 5127 . -dm_plex_view_scale <num> - Scale the TikZ 5128 . -dm_plex_print_fem <num> - View FEM assembly information, such as element vectors and matrices 5129 - -dm_plex_print_fvm <num> - View FVM assembly information, such as flux updates 5130 5131 Level: intermediate 5132 5133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection` 5134 M*/ 5135 5136 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm) 5137 { 5138 DM_Plex *mesh; 5139 PetscInt unit; 5140 5141 PetscFunctionBegin; 5142 PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite)); 5143 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5144 PetscCall(PetscNew(&mesh)); 5145 dm->reorderSection = DM_REORDER_DEFAULT_NOTSET; 5146 dm->data = mesh; 5147 5148 mesh->refct = 1; 5149 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection)); 5150 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection)); 5151 mesh->refinementUniform = PETSC_TRUE; 5152 mesh->refinementLimit = -1.0; 5153 mesh->distDefault = PETSC_TRUE; 5154 mesh->reorderDefault = DM_REORDER_DEFAULT_NOTSET; 5155 mesh->distributionName = NULL; 5156 mesh->interpolated = DMPLEX_INTERPOLATED_INVALID; 5157 mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID; 5158 5159 PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner)); 5160 mesh->remeshBd = PETSC_FALSE; 5161 5162 for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0; 5163 5164 mesh->depthState = -1; 5165 mesh->celltypeState = -1; 5166 mesh->printTol = 1.0e-10; 5167 mesh->nonempty_comm = MPI_COMM_SELF; 5168 5169 PetscCall(DMInitialize_Plex(dm)); 5170 PetscFunctionReturn(PETSC_SUCCESS); 5171 } 5172 5173 /*@ 5174 DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram. 5175 5176 Collective 5177 5178 Input Parameter: 5179 . comm - The communicator for the `DMPLEX` object 5180 5181 Output Parameter: 5182 . mesh - The `DMPLEX` object 5183 5184 Level: beginner 5185 5186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()` 5187 @*/ 5188 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh) 5189 { 5190 PetscFunctionBegin; 5191 PetscAssertPointer(mesh, 2); 5192 PetscCall(DMCreate(comm, mesh)); 5193 PetscCall(DMSetType(*mesh, DMPLEX)); 5194 PetscFunctionReturn(PETSC_SUCCESS); 5195 } 5196 5197 /*@C 5198 DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype 5199 5200 Collective; No Fortran Support 5201 5202 Input Parameters: 5203 + dm - The `DM` 5204 . numCells - The number of cells owned by this process 5205 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 5206 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 5207 . numCorners - The number of vertices for each cell 5208 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5209 5210 Output Parameters: 5211 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5212 - verticesAdjSaved - (Optional) vertex adjacency array 5213 5214 Level: advanced 5215 5216 Notes: 5217 Two triangles sharing a face 5218 .vb 5219 5220 2 5221 / | \ 5222 / | \ 5223 / | \ 5224 0 0 | 1 3 5225 \ | / 5226 \ | / 5227 \ | / 5228 1 5229 .ve 5230 would have input 5231 .vb 5232 numCells = 2, numVertices = 4 5233 cells = [0 1 2 1 3 2] 5234 .ve 5235 which would result in the `DMPLEX` 5236 .vb 5237 5238 4 5239 / | \ 5240 / | \ 5241 / | \ 5242 2 0 | 1 5 5243 \ | / 5244 \ | / 5245 \ | / 5246 3 5247 .ve 5248 5249 Vertices are implicitly numbered consecutively 0,...,NVertices. 5250 Each rank owns a chunk of numVertices consecutive vertices. 5251 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 5252 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 5253 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 5254 5255 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 5256 5257 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 5258 `PetscSF` 5259 @*/ 5260 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved) 5261 { 5262 PetscSF sfPoint; 5263 PetscLayout layout; 5264 PetscInt numVerticesAdj, *verticesAdj, *cones, c, p; 5265 5266 PetscFunctionBegin; 5267 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 5268 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5269 /* Get/check global number of vertices */ 5270 { 5271 PetscInt NVerticesInCells, i; 5272 const PetscInt len = numCells * numCorners; 5273 5274 /* NVerticesInCells = max(cells) + 1 */ 5275 NVerticesInCells = PETSC_INT_MIN; 5276 for (i = 0; i < len; i++) 5277 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5278 ++NVerticesInCells; 5279 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 5280 5281 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 5282 else 5283 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); 5284 } 5285 /* Count locally unique vertices */ 5286 { 5287 PetscHSetI vhash; 5288 PetscInt off = 0; 5289 5290 PetscCall(PetscHSetICreate(&vhash)); 5291 for (c = 0; c < numCells; ++c) { 5292 for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p])); 5293 } 5294 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 5295 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 5296 else verticesAdj = *verticesAdjSaved; 5297 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 5298 PetscCall(PetscHSetIDestroy(&vhash)); 5299 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 5300 } 5301 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 5302 /* Create cones */ 5303 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 5304 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5305 PetscCall(DMSetUp(dm)); 5306 PetscCall(DMPlexGetCones(dm, &cones)); 5307 for (c = 0; c < numCells; ++c) { 5308 for (p = 0; p < numCorners; ++p) { 5309 const PetscInt gv = cells[c * numCorners + p]; 5310 PetscInt lv; 5311 5312 /* Positions within verticesAdj form 0-based local vertex numbering; 5313 we need to shift it by numCells to get correct DAG points (cells go first) */ 5314 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 5315 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 5316 cones[c * numCorners + p] = lv + numCells; 5317 } 5318 } 5319 /* Build point sf */ 5320 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 5321 PetscCall(PetscLayoutSetSize(layout, NVertices)); 5322 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 5323 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 5324 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 5325 PetscCall(PetscLayoutDestroy(&layout)); 5326 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 5327 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 5328 if (dm->sf) { 5329 const char *prefix; 5330 5331 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 5332 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 5333 } 5334 PetscCall(DMSetPointSF(dm, sfPoint)); 5335 PetscCall(PetscSFDestroy(&sfPoint)); 5336 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 5337 /* Fill in the rest of the topology structure */ 5338 PetscCall(DMPlexSymmetrize(dm)); 5339 PetscCall(DMPlexStratify(dm)); 5340 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5341 PetscFunctionReturn(PETSC_SUCCESS); 5342 } 5343 5344 /*@C 5345 DMPlexBuildFromCellSectionParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) allowing multiple celltypes 5346 5347 Collective; No Fortran Support 5348 5349 Input Parameters: 5350 + dm - The `DM` 5351 . numCells - The number of cells owned by this process 5352 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 5353 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 5354 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells) 5355 - cells - An array of the global vertex numbers for each cell 5356 5357 Output Parameters: 5358 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5359 - verticesAdjSaved - (Optional) vertex adjacency array 5360 5361 Level: advanced 5362 5363 Notes: 5364 A triangle and quadrilateral sharing a face 5365 .vb 5366 2----------3 5367 / | | 5368 / | | 5369 / | | 5370 0 0 | 1 | 5371 \ | | 5372 \ | | 5373 \ | | 5374 1----------4 5375 .ve 5376 would have input 5377 .vb 5378 numCells = 2, numVertices = 5 5379 cells = [0 1 2 1 4 3 2] 5380 .ve 5381 which would result in the `DMPLEX` 5382 .vb 5383 4----------5 5384 / | | 5385 / | | 5386 / | | 5387 2 0 | 1 | 5388 \ | | 5389 \ | | 5390 \ | | 5391 3----------6 5392 .ve 5393 5394 Vertices are implicitly numbered consecutively 0,...,NVertices. 5395 Each rank owns a chunk of numVertices consecutive vertices. 5396 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 5397 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 5398 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 5399 5400 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 5401 5402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexCreateFromCellSectionParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 5403 `PetscSF` 5404 @*/ 5405 PetscErrorCode DMPlexBuildFromCellSectionParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved) 5406 { 5407 PetscSF sfPoint; 5408 PetscLayout layout; 5409 PetscInt numVerticesAdj, *verticesAdj, *cones, cStart, cEnd, len; 5410 5411 PetscFunctionBegin; 5412 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 5413 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5414 PetscCall(PetscSectionGetChart(cellSection, &cStart, &cEnd)); 5415 PetscCall(PetscSectionGetStorageSize(cellSection, &len)); 5416 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); 5417 /* Get/check global number of vertices */ 5418 { 5419 PetscInt NVerticesInCells; 5420 5421 /* NVerticesInCells = max(cells) + 1 */ 5422 NVerticesInCells = PETSC_MIN_INT; 5423 for (PetscInt i = 0; i < len; i++) 5424 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5425 ++NVerticesInCells; 5426 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 5427 5428 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 5429 else 5430 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); 5431 } 5432 /* Count locally unique vertices */ 5433 { 5434 PetscHSetI vhash; 5435 PetscInt off = 0; 5436 5437 PetscCall(PetscHSetICreate(&vhash)); 5438 for (PetscInt i = 0; i < len; i++) PetscCall(PetscHSetIAdd(vhash, cells[i])); 5439 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 5440 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 5441 else verticesAdj = *verticesAdjSaved; 5442 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 5443 PetscCall(PetscHSetIDestroy(&vhash)); 5444 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 5445 } 5446 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 5447 /* Create cones */ 5448 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 5449 for (PetscInt c = 0; c < numCells; ++c) { 5450 PetscInt dof; 5451 5452 PetscCall(PetscSectionGetDof(cellSection, c, &dof)); 5453 PetscCall(DMPlexSetConeSize(dm, c, dof)); 5454 } 5455 PetscCall(DMSetUp(dm)); 5456 PetscCall(DMPlexGetCones(dm, &cones)); 5457 for (PetscInt c = 0; c < numCells; ++c) { 5458 PetscInt dof, off; 5459 5460 PetscCall(PetscSectionGetDof(cellSection, c, &dof)); 5461 PetscCall(PetscSectionGetOffset(cellSection, c, &off)); 5462 for (PetscInt p = off; p < off + dof; ++p) { 5463 const PetscInt gv = cells[p]; 5464 PetscInt lv; 5465 5466 /* Positions within verticesAdj form 0-based local vertex numbering; 5467 we need to shift it by numCells to get correct DAG points (cells go first) */ 5468 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 5469 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 5470 cones[p] = lv + numCells; 5471 } 5472 } 5473 /* Build point sf */ 5474 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 5475 PetscCall(PetscLayoutSetSize(layout, NVertices)); 5476 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 5477 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 5478 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 5479 PetscCall(PetscLayoutDestroy(&layout)); 5480 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 5481 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 5482 if (dm->sf) { 5483 const char *prefix; 5484 5485 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 5486 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 5487 } 5488 PetscCall(DMSetPointSF(dm, sfPoint)); 5489 PetscCall(PetscSFDestroy(&sfPoint)); 5490 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 5491 /* Fill in the rest of the topology structure */ 5492 PetscCall(DMPlexSymmetrize(dm)); 5493 PetscCall(DMPlexStratify(dm)); 5494 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5495 PetscFunctionReturn(PETSC_SUCCESS); 5496 } 5497 5498 /*@ 5499 DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 5500 5501 Collective; No Fortran Support 5502 5503 Input Parameters: 5504 + dm - The `DM` 5505 . spaceDim - The spatial dimension used for coordinates 5506 . sfVert - `PetscSF` describing complete vertex ownership 5507 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5508 5509 Level: advanced 5510 5511 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()` 5512 @*/ 5513 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[]) 5514 { 5515 PetscSection coordSection; 5516 Vec coordinates; 5517 PetscScalar *coords; 5518 PetscInt numVertices, numVerticesAdj, coordSize, v, vStart, vEnd; 5519 5520 PetscFunctionBegin; 5521 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5522 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 5523 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 5524 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 5525 PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL)); 5526 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); 5527 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5528 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5529 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 5530 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 5531 for (v = vStart; v < vEnd; ++v) { 5532 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 5533 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 5534 } 5535 PetscCall(PetscSectionSetUp(coordSection)); 5536 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5537 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates)); 5538 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 5539 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5540 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5541 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5542 PetscCall(VecGetArray(coordinates, &coords)); 5543 { 5544 MPI_Datatype coordtype; 5545 5546 /* Need a temp buffer for coords if we have complex/single */ 5547 PetscCallMPI(MPI_Type_contiguous((PetscMPIInt)spaceDim, MPIU_SCALAR, &coordtype)); 5548 PetscCallMPI(MPI_Type_commit(&coordtype)); 5549 #if defined(PETSC_USE_COMPLEX) 5550 { 5551 PetscScalar *svertexCoords; 5552 PetscInt i; 5553 PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords)); 5554 for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i]; 5555 PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 5556 PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 5557 PetscCall(PetscFree(svertexCoords)); 5558 } 5559 #else 5560 PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 5561 PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 5562 #endif 5563 PetscCallMPI(MPI_Type_free(&coordtype)); 5564 } 5565 PetscCall(VecRestoreArray(coordinates, &coords)); 5566 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5567 PetscCall(VecDestroy(&coordinates)); 5568 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5569 PetscFunctionReturn(PETSC_SUCCESS); 5570 } 5571 5572 /*@ 5573 DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype 5574 5575 Collective 5576 5577 Input Parameters: 5578 + comm - The communicator 5579 . dim - The topological dimension of the mesh 5580 . numCells - The number of cells owned by this process 5581 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 5582 . NVertices - The global number of vertices, or `PETSC_DECIDE` 5583 . numCorners - The number of vertices for each cell 5584 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5585 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5586 . spaceDim - The spatial dimension used for coordinates 5587 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5588 5589 Output Parameters: 5590 + dm - The `DM` 5591 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5592 - verticesAdj - (Optional) vertex adjacency array 5593 5594 Level: intermediate 5595 5596 Notes: 5597 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 5598 `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 5599 5600 See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters. 5601 5602 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 5603 5604 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5605 @*/ 5606 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) 5607 { 5608 PetscSF sfVert; 5609 5610 PetscFunctionBegin; 5611 PetscCall(DMCreate(comm, dm)); 5612 PetscCall(DMSetType(*dm, DMPLEX)); 5613 PetscValidLogicalCollectiveInt(*dm, dim, 2); 5614 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 5615 PetscCall(DMSetDimension(*dm, dim)); 5616 PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj)); 5617 if (interpolate) { 5618 DM idm; 5619 5620 PetscCall(DMPlexInterpolate(*dm, &idm)); 5621 PetscCall(DMDestroy(dm)); 5622 *dm = idm; 5623 } 5624 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 5625 if (vertexSF) *vertexSF = sfVert; 5626 else PetscCall(PetscSFDestroy(&sfVert)); 5627 PetscFunctionReturn(PETSC_SUCCESS); 5628 } 5629 5630 /*@ 5631 DMPlexCreateFromCellSectionParallel - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) and supports multiple celltypes 5632 5633 Collective 5634 5635 Input Parameters: 5636 + comm - The communicator 5637 . dim - The topological dimension of the mesh 5638 . numCells - The number of cells owned by this process 5639 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 5640 . NVertices - The global number of vertices, or `PETSC_DECIDE` 5641 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells) 5642 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5643 . cells - An array of the global vertex numbers for each cell 5644 . spaceDim - The spatial dimension used for coordinates 5645 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5646 5647 Output Parameters: 5648 + dm - The `DM` 5649 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5650 - verticesAdj - (Optional) vertex adjacency array 5651 5652 Level: intermediate 5653 5654 Notes: 5655 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 5656 `DMPlexBuildFromCellSectionParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 5657 5658 See `DMPlexBuildFromCellSectionParallel()` for an example and details about the topology-related parameters. 5659 5660 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 5661 5662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5663 @*/ 5664 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) 5665 { 5666 PetscSF sfVert; 5667 5668 PetscFunctionBegin; 5669 PetscCall(DMCreate(comm, dm)); 5670 PetscCall(DMSetType(*dm, DMPLEX)); 5671 PetscValidLogicalCollectiveInt(*dm, dim, 2); 5672 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 5673 PetscCall(DMSetDimension(*dm, dim)); 5674 PetscCall(DMPlexBuildFromCellSectionParallel(*dm, numCells, numVertices, NVertices, cellSection, cells, &sfVert, verticesAdj)); 5675 if (interpolate) { 5676 DM idm; 5677 5678 PetscCall(DMPlexInterpolate(*dm, &idm)); 5679 PetscCall(DMDestroy(dm)); 5680 *dm = idm; 5681 } 5682 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 5683 if (vertexSF) *vertexSF = sfVert; 5684 else PetscCall(PetscSFDestroy(&sfVert)); 5685 PetscFunctionReturn(PETSC_SUCCESS); 5686 } 5687 5688 /*@ 5689 DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 5690 5691 Collective; No Fortran Support 5692 5693 Input Parameters: 5694 + dm - The `DM` 5695 . numCells - The number of cells owned by this process 5696 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE` 5697 . numCorners - The number of vertices for each cell 5698 - cells - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell 5699 5700 Level: advanced 5701 5702 Notes: 5703 Two triangles sharing a face 5704 .vb 5705 5706 2 5707 / | \ 5708 / | \ 5709 / | \ 5710 0 0 | 1 3 5711 \ | / 5712 \ | / 5713 \ | / 5714 1 5715 .ve 5716 would have input 5717 .vb 5718 numCells = 2, numVertices = 4 5719 cells = [0 1 2 1 3 2] 5720 .ve 5721 which would result in the `DMPLEX` 5722 .vb 5723 5724 4 5725 / | \ 5726 / | \ 5727 / | \ 5728 2 0 | 1 5 5729 \ | / 5730 \ | / 5731 \ | / 5732 3 5733 .ve 5734 5735 If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1. 5736 5737 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()` 5738 @*/ 5739 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[]) 5740 { 5741 PetscInt *cones, c, p, dim; 5742 5743 PetscFunctionBegin; 5744 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5745 PetscCall(DMGetDimension(dm, &dim)); 5746 /* Get/check global number of vertices */ 5747 { 5748 PetscInt NVerticesInCells, i; 5749 const PetscInt len = numCells * numCorners; 5750 5751 /* NVerticesInCells = max(cells) + 1 */ 5752 NVerticesInCells = PETSC_INT_MIN; 5753 for (i = 0; i < len; i++) 5754 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5755 ++NVerticesInCells; 5756 5757 if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells; 5758 else 5759 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); 5760 } 5761 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 5762 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5763 PetscCall(DMSetUp(dm)); 5764 PetscCall(DMPlexGetCones(dm, &cones)); 5765 for (c = 0; c < numCells; ++c) { 5766 for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells; 5767 } 5768 PetscCall(DMPlexSymmetrize(dm)); 5769 PetscCall(DMPlexStratify(dm)); 5770 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5771 PetscFunctionReturn(PETSC_SUCCESS); 5772 } 5773 5774 /*@ 5775 DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 5776 5777 Collective 5778 5779 Input Parameters: 5780 + dm - The `DM` 5781 . spaceDim - The spatial dimension used for coordinates 5782 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 5783 5784 Level: advanced 5785 5786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()` 5787 @*/ 5788 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[]) 5789 { 5790 PetscSection coordSection; 5791 Vec coordinates; 5792 DM cdm; 5793 PetscScalar *coords; 5794 PetscInt v, vStart, vEnd, d; 5795 5796 PetscFunctionBegin; 5797 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5798 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 5799 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 5800 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 5801 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5802 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5803 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 5804 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 5805 for (v = vStart; v < vEnd; ++v) { 5806 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 5807 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 5808 } 5809 PetscCall(PetscSectionSetUp(coordSection)); 5810 5811 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5812 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 5813 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 5814 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5815 PetscCall(VecGetArrayWrite(coordinates, &coords)); 5816 for (v = 0; v < vEnd - vStart; ++v) { 5817 for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d]; 5818 } 5819 PetscCall(VecRestoreArrayWrite(coordinates, &coords)); 5820 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5821 PetscCall(VecDestroy(&coordinates)); 5822 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 5823 PetscFunctionReturn(PETSC_SUCCESS); 5824 } 5825 5826 /*@ 5827 DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input 5828 5829 Collective 5830 5831 Input Parameters: 5832 + comm - The communicator 5833 . dim - The topological dimension of the mesh 5834 . numCells - The number of cells, only on process 0 5835 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0 5836 . numCorners - The number of vertices for each cell, only on process 0 5837 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 5838 . cells - An array of numCells*numCorners numbers, the vertices for each cell, only on process 0 5839 . spaceDim - The spatial dimension used for coordinates 5840 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex, only on process 0 5841 5842 Output Parameter: 5843 . dm - The `DM`, which only has points on process 0 5844 5845 Level: intermediate 5846 5847 Notes: 5848 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`, 5849 `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()` 5850 5851 See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters. 5852 See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters. 5853 See `DMPlexCreateFromCellListParallelPetsc()` for parallel input 5854 5855 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 5856 @*/ 5857 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) 5858 { 5859 PetscMPIInt rank; 5860 5861 PetscFunctionBegin; 5862 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."); 5863 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5864 PetscCall(DMCreate(comm, dm)); 5865 PetscCall(DMSetType(*dm, DMPLEX)); 5866 PetscCall(DMSetDimension(*dm, dim)); 5867 if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells)); 5868 else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL)); 5869 if (interpolate) { 5870 DM idm; 5871 5872 PetscCall(DMPlexInterpolate(*dm, &idm)); 5873 PetscCall(DMDestroy(dm)); 5874 *dm = idm; 5875 } 5876 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords)); 5877 else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL)); 5878 PetscFunctionReturn(PETSC_SUCCESS); 5879 } 5880 5881 /*@ 5882 DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM` 5883 5884 Input Parameters: 5885 + dm - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()` 5886 . depth - The depth of the DAG 5887 . numPoints - Array of size depth + 1 containing the number of points at each `depth` 5888 . coneSize - The cone size of each point 5889 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point 5890 . coneOrientations - The orientation of each cone point 5891 - vertexCoords - An array of `numPoints`[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via `DMSetCoordinateDim()` 5892 5893 Output Parameter: 5894 . dm - The `DM` 5895 5896 Level: advanced 5897 5898 Note: 5899 Two triangles sharing a face would have input 5900 .vb 5901 depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0] 5902 cones = [2 3 4 3 5 4], coneOrientations = [0 0 0 0 0 0] 5903 vertexCoords = [-1.0 0.0 0.0 -1.0 0.0 1.0 1.0 0.0] 5904 .ve 5905 which would result in the DMPlex 5906 .vb 5907 4 5908 / | \ 5909 / | \ 5910 / | \ 5911 2 0 | 1 5 5912 \ | / 5913 \ | / 5914 \ | / 5915 3 5916 .ve 5917 Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()` 5918 5919 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 5920 @*/ 5921 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[]) 5922 { 5923 Vec coordinates; 5924 PetscSection coordSection; 5925 PetscScalar *coords; 5926 PetscInt coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off; 5927 5928 PetscFunctionBegin; 5929 PetscCall(DMGetDimension(dm, &dim)); 5930 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 5931 PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim); 5932 for (d = 0; d <= depth; ++d) pEnd += numPoints[d]; 5933 PetscCall(DMPlexSetChart(dm, pStart, pEnd)); 5934 for (p = pStart; p < pEnd; ++p) { 5935 PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart])); 5936 if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart; 5937 } 5938 PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]); 5939 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 5940 for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) { 5941 PetscCall(DMPlexSetCone(dm, p, &cones[off])); 5942 PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off])); 5943 } 5944 PetscCall(DMPlexSymmetrize(dm)); 5945 PetscCall(DMPlexStratify(dm)); 5946 /* Build coordinates */ 5947 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 5948 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 5949 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed)); 5950 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0])); 5951 for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) { 5952 PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed)); 5953 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed)); 5954 } 5955 PetscCall(PetscSectionSetUp(coordSection)); 5956 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 5957 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 5958 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 5959 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 5960 PetscCall(VecSetBlockSize(coordinates, dimEmbed)); 5961 PetscCall(VecSetType(coordinates, VECSTANDARD)); 5962 if (vertexCoords) { 5963 PetscCall(VecGetArray(coordinates, &coords)); 5964 for (v = 0; v < numPoints[0]; ++v) { 5965 PetscInt off; 5966 5967 PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off)); 5968 for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d]; 5969 } 5970 } 5971 PetscCall(VecRestoreArray(coordinates, &coords)); 5972 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 5973 PetscCall(VecDestroy(&coordinates)); 5974 PetscFunctionReturn(PETSC_SUCCESS); 5975 } 5976 5977 /* 5978 DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file. 5979 5980 Collective 5981 5982 + comm - The MPI communicator 5983 . filename - Name of the .dat file 5984 - interpolate - Create faces and edges in the mesh 5985 5986 Output Parameter: 5987 . dm - The `DM` object representing the mesh 5988 5989 Level: beginner 5990 5991 Note: 5992 The format is the simplest possible: 5993 .vb 5994 dim Ne Nv Nc Nl 5995 v_1 v_2 ... v_Nc 5996 ... 5997 x y z marker_1 ... marker_Nl 5998 .ve 5999 6000 Developer Note: 6001 Should use a `PetscViewer` not a filename 6002 6003 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()` 6004 */ 6005 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 6006 { 6007 DMLabel marker; 6008 PetscViewer viewer; 6009 Vec coordinates; 6010 PetscSection coordSection; 6011 PetscScalar *coords; 6012 char line[PETSC_MAX_PATH_LEN]; 6013 PetscInt cdim, coordSize, v, c, d; 6014 PetscMPIInt rank; 6015 int snum, dim, Nv, Nc, Ncn, Nl; 6016 6017 PetscFunctionBegin; 6018 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6019 PetscCall(PetscViewerCreate(comm, &viewer)); 6020 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII)); 6021 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 6022 PetscCall(PetscViewerFileSetName(viewer, filename)); 6023 if (rank == 0) { 6024 PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING)); 6025 snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl); 6026 PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6027 } else { 6028 Nc = Nv = Ncn = Nl = 0; 6029 } 6030 PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm)); 6031 cdim = (PetscInt)dim; 6032 PetscCall(DMCreate(comm, dm)); 6033 PetscCall(DMSetType(*dm, DMPLEX)); 6034 PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv)); 6035 PetscCall(DMSetDimension(*dm, (PetscInt)dim)); 6036 PetscCall(DMSetCoordinateDim(*dm, cdim)); 6037 /* Read topology */ 6038 if (rank == 0) { 6039 char format[PETSC_MAX_PATH_LEN]; 6040 PetscInt cone[8]; 6041 int vbuf[8], v; 6042 6043 for (c = 0; c < Ncn; ++c) { 6044 format[c * 3 + 0] = '%'; 6045 format[c * 3 + 1] = 'd'; 6046 format[c * 3 + 2] = ' '; 6047 } 6048 format[Ncn * 3 - 1] = '\0'; 6049 for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn)); 6050 PetscCall(DMSetUp(*dm)); 6051 for (c = 0; c < Nc; ++c) { 6052 PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING)); 6053 switch (Ncn) { 6054 case 2: 6055 snum = sscanf(line, format, &vbuf[0], &vbuf[1]); 6056 break; 6057 case 3: 6058 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]); 6059 break; 6060 case 4: 6061 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]); 6062 break; 6063 case 6: 6064 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]); 6065 break; 6066 case 8: 6067 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]); 6068 break; 6069 default: 6070 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn); 6071 } 6072 PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6073 for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc; 6074 /* Hexahedra are inverted */ 6075 if (Ncn == 8) { 6076 PetscInt tmp = cone[1]; 6077 cone[1] = cone[3]; 6078 cone[3] = tmp; 6079 } 6080 PetscCall(DMPlexSetCone(*dm, c, cone)); 6081 } 6082 } 6083 PetscCall(DMPlexSymmetrize(*dm)); 6084 PetscCall(DMPlexStratify(*dm)); 6085 /* Read coordinates */ 6086 PetscCall(DMGetCoordinateSection(*dm, &coordSection)); 6087 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6088 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 6089 PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv)); 6090 for (v = Nc; v < Nc + Nv; ++v) { 6091 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 6092 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 6093 } 6094 PetscCall(PetscSectionSetUp(coordSection)); 6095 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6096 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 6097 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6098 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6099 PetscCall(VecSetBlockSize(coordinates, cdim)); 6100 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6101 PetscCall(VecGetArray(coordinates, &coords)); 6102 if (rank == 0) { 6103 char format[PETSC_MAX_PATH_LEN]; 6104 double x[3]; 6105 int l, val[3]; 6106 6107 if (Nl) { 6108 for (l = 0; l < Nl; ++l) { 6109 format[l * 3 + 0] = '%'; 6110 format[l * 3 + 1] = 'd'; 6111 format[l * 3 + 2] = ' '; 6112 } 6113 format[Nl * 3 - 1] = '\0'; 6114 PetscCall(DMCreateLabel(*dm, "marker")); 6115 PetscCall(DMGetLabel(*dm, "marker", &marker)); 6116 } 6117 for (v = 0; v < Nv; ++v) { 6118 PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING)); 6119 snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]); 6120 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6121 switch (Nl) { 6122 case 0: 6123 snum = 0; 6124 break; 6125 case 1: 6126 snum = sscanf(line, format, &val[0]); 6127 break; 6128 case 2: 6129 snum = sscanf(line, format, &val[0], &val[1]); 6130 break; 6131 case 3: 6132 snum = sscanf(line, format, &val[0], &val[1], &val[2]); 6133 break; 6134 default: 6135 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl); 6136 } 6137 PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6138 for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d]; 6139 for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l])); 6140 } 6141 } 6142 PetscCall(VecRestoreArray(coordinates, &coords)); 6143 PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 6144 PetscCall(VecDestroy(&coordinates)); 6145 PetscCall(PetscViewerDestroy(&viewer)); 6146 if (interpolate) { 6147 DM idm; 6148 DMLabel bdlabel; 6149 6150 PetscCall(DMPlexInterpolate(*dm, &idm)); 6151 PetscCall(DMDestroy(dm)); 6152 *dm = idm; 6153 6154 if (!Nl) { 6155 PetscCall(DMCreateLabel(*dm, "marker")); 6156 PetscCall(DMGetLabel(*dm, "marker", &bdlabel)); 6157 PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel)); 6158 PetscCall(DMPlexLabelComplete(*dm, bdlabel)); 6159 } 6160 } 6161 PetscFunctionReturn(PETSC_SUCCESS); 6162 } 6163 6164 /*@ 6165 DMPlexCreateFromFile - This takes a filename and produces a `DM` 6166 6167 Collective 6168 6169 Input Parameters: 6170 + comm - The communicator 6171 . filename - A file name 6172 . plexname - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats 6173 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 6174 6175 Output Parameter: 6176 . dm - The `DM` 6177 6178 Options Database Key: 6179 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5 6180 6181 Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. 6182 $ -dm_plex_create_viewer_hdf5_collective 6183 6184 Level: beginner 6185 6186 Notes: 6187 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 6188 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 6189 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 6190 The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally 6191 calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats. 6192 6193 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()` 6194 @*/ 6195 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm) 6196 { 6197 const char extGmsh[] = ".msh"; 6198 const char extGmsh2[] = ".msh2"; 6199 const char extGmsh4[] = ".msh4"; 6200 const char extCGNS[] = ".cgns"; 6201 const char extExodus[] = ".exo"; 6202 const char extExodus_e[] = ".e"; 6203 const char extGenesis[] = ".gen"; 6204 const char extFluent[] = ".cas"; 6205 const char extHDF5[] = ".h5"; 6206 const char extXDMFHDF5[] = ".xdmf.h5"; 6207 const char extPLY[] = ".ply"; 6208 const char extEGADSLite[] = ".egadslite"; 6209 const char extEGADS[] = ".egads"; 6210 const char extIGES[] = ".igs"; 6211 const char extSTEP[] = ".stp"; 6212 const char extCV[] = ".dat"; 6213 size_t len; 6214 PetscBool isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSLite, isEGADS, isIGES, isSTEP, isCV, isXDMFHDF5; 6215 PetscMPIInt rank; 6216 6217 PetscFunctionBegin; 6218 PetscAssertPointer(filename, 2); 6219 if (plexname) PetscAssertPointer(plexname, 3); 6220 PetscAssertPointer(dm, 5); 6221 PetscCall(DMInitializePackage()); 6222 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 6223 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6224 PetscCall(PetscStrlen(filename, &len)); 6225 PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path"); 6226 6227 #define CheckExtension(extension__, is_extension__) \ 6228 do { \ 6229 PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \ 6230 /* don't count the null-terminator at the end */ \ 6231 const size_t ext_len = sizeof(extension__) - 1; \ 6232 if (len < ext_len) { \ 6233 is_extension__ = PETSC_FALSE; \ 6234 } else { \ 6235 PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \ 6236 } \ 6237 } while (0) 6238 6239 CheckExtension(extGmsh, isGmsh); 6240 CheckExtension(extGmsh2, isGmsh2); 6241 CheckExtension(extGmsh4, isGmsh4); 6242 CheckExtension(extCGNS, isCGNS); 6243 CheckExtension(extExodus, isExodus); 6244 if (!isExodus) CheckExtension(extExodus_e, isExodus); 6245 CheckExtension(extGenesis, isGenesis); 6246 CheckExtension(extFluent, isFluent); 6247 CheckExtension(extHDF5, isHDF5); 6248 CheckExtension(extPLY, isPLY); 6249 CheckExtension(extEGADSLite, isEGADSLite); 6250 CheckExtension(extEGADS, isEGADS); 6251 CheckExtension(extIGES, isIGES); 6252 CheckExtension(extSTEP, isSTEP); 6253 CheckExtension(extCV, isCV); 6254 CheckExtension(extXDMFHDF5, isXDMFHDF5); 6255 6256 #undef CheckExtension 6257 6258 if (isGmsh || isGmsh2 || isGmsh4) { 6259 PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm)); 6260 } else if (isCGNS) { 6261 PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm)); 6262 } else if (isExodus || isGenesis) { 6263 PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm)); 6264 } else if (isFluent) { 6265 PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm)); 6266 } else if (isHDF5) { 6267 PetscViewer viewer; 6268 6269 /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */ 6270 PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL)); 6271 PetscCall(PetscViewerCreate(comm, &viewer)); 6272 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5)); 6273 PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_")); 6274 PetscCall(PetscViewerSetFromOptions(viewer)); 6275 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 6276 PetscCall(PetscViewerFileSetName(viewer, filename)); 6277 6278 PetscCall(DMCreate(comm, dm)); 6279 PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 6280 PetscCall(DMSetType(*dm, DMPLEX)); 6281 if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF)); 6282 PetscCall(DMLoad(*dm, viewer)); 6283 if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer)); 6284 PetscCall(PetscViewerDestroy(&viewer)); 6285 6286 if (interpolate) { 6287 DM idm; 6288 6289 PetscCall(DMPlexInterpolate(*dm, &idm)); 6290 PetscCall(DMDestroy(dm)); 6291 *dm = idm; 6292 } 6293 } else if (isPLY) { 6294 PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm)); 6295 } else if (isEGADSLite || isEGADS || isIGES || isSTEP) { 6296 if (isEGADSLite) PetscCall(DMPlexCreateEGADSLiteFromFile(comm, filename, dm)); 6297 else PetscCall(DMPlexCreateEGADSFromFile(comm, filename, dm)); 6298 if (!interpolate) { 6299 DM udm; 6300 6301 PetscCall(DMPlexUninterpolate(*dm, &udm)); 6302 PetscCall(DMDestroy(dm)); 6303 *dm = udm; 6304 } 6305 } else if (isCV) { 6306 PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm)); 6307 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename); 6308 PetscCall(PetscStrlen(plexname, &len)); 6309 if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 6310 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 6311 PetscFunctionReturn(PETSC_SUCCESS); 6312 } 6313 6314 /*@ 6315 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. 6316 6317 Input Parameters: 6318 + tr - The `DMPlexTransform` 6319 - prefix - An options prefix, or NULL 6320 6321 Output Parameter: 6322 . dm - The `DM` 6323 6324 Level: beginner 6325 6326 Notes: 6327 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. 6328 6329 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 6330 @*/ 6331 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm) 6332 { 6333 DM bdm, bcdm, cdm; 6334 Vec coordinates, coordinatesNew; 6335 PetscSection cs; 6336 PetscInt cdim, Nl; 6337 6338 PetscFunctionBegin; 6339 PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm)); 6340 PetscCall(DMSetType(*dm, DMPLEX)); 6341 ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL; 6342 // Handle coordinates 6343 PetscCall(DMPlexTransformGetDM(tr, &bdm)); 6344 PetscCall(DMPlexTransformSetDimensions(tr, bdm, *dm)); 6345 PetscCall(DMGetCoordinateDim(*dm, &cdim)); 6346 PetscCall(DMGetCoordinateDM(bdm, &bcdm)); 6347 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 6348 PetscCall(DMCopyDisc(bcdm, cdm)); 6349 PetscCall(DMGetLocalSection(cdm, &cs)); 6350 PetscCall(PetscSectionSetNumFields(cs, 1)); 6351 PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim)); 6352 PetscCall(DMGetCoordinatesLocal(bdm, &coordinates)); 6353 PetscCall(VecDuplicate(coordinates, &coordinatesNew)); 6354 PetscCall(VecCopy(coordinates, coordinatesNew)); 6355 PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew)); 6356 PetscCall(VecDestroy(&coordinatesNew)); 6357 6358 PetscCall(PetscObjectReference((PetscObject)tr)); 6359 PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr)); 6360 ((DM_Plex *)(*dm)->data)->tr = tr; 6361 PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE)); 6362 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix)); 6363 PetscCall(DMSetFromOptions(*dm)); 6364 6365 PetscCall(DMGetNumLabels(bdm, &Nl)); 6366 for (PetscInt l = 0; l < Nl; ++l) { 6367 DMLabel label, labelNew; 6368 const char *lname; 6369 PetscBool isDepth, isCellType; 6370 6371 PetscCall(DMGetLabelName(bdm, l, &lname)); 6372 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 6373 if (isDepth) continue; 6374 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 6375 if (isCellType) continue; 6376 PetscCall(DMCreateLabel(*dm, lname)); 6377 PetscCall(DMGetLabel(bdm, lname, &label)); 6378 PetscCall(DMGetLabel(*dm, lname, &labelNew)); 6379 PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL)); 6380 PetscCall(DMLabelEphemeralSetLabel(labelNew, label)); 6381 PetscCall(DMLabelEphemeralSetTransform(labelNew, tr)); 6382 PetscCall(DMLabelSetUp(labelNew)); 6383 } 6384 PetscFunctionReturn(PETSC_SUCCESS); 6385 } 6386