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