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