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