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