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