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