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