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