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