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