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