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