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