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