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