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