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