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