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