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, cdm, cdmf; 4292 Vec X; 4293 PetscScalar *x; 4294 4295 PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf)); 4296 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4297 PetscCall(DMGetCoordinateDM(dmf, &cdmf)); 4298 PetscCall(DMCopyDisc(cdm, cdmf)); 4299 PetscCall(DMPlexReplace_Internal(dm, &dmf)); 4300 4301 PetscCall(DMGetCoordinatesLocal(dm, &X)); 4302 PetscCall(VecGetLocalSize(X, &m)); 4303 PetscCall(VecGetArray(X, &x)); 4304 for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i])); 4305 PetscCall(VecRestoreArray(X, &x)); 4306 } 4307 4308 // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices. 4309 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 4310 PetscCall(DMPlexLabelComplete(dm, label)); 4311 4312 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 4313 4314 if (thickness > 0) { 4315 DM edm, cdm, ecdm; 4316 DMPlexTransform tr; 4317 const char *prefix; 4318 PetscOptions options; 4319 // Code from DMPlexExtrude 4320 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 4321 PetscCall(DMPlexTransformSetDM(tr, dm)); 4322 PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDETYPE)); 4323 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 4324 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 4325 PetscCall(PetscObjectGetOptions((PetscObject)dm, &options)); 4326 PetscCall(PetscObjectSetOptions((PetscObject)tr, options)); 4327 PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers)); 4328 PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness)); 4329 PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE)); 4330 PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE)); 4331 PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc)); 4332 PetscCall(DMPlexTransformSetFromOptions(tr)); 4333 PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL)); 4334 PetscCall(DMPlexTransformSetUp(tr)); 4335 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view")); 4336 PetscCall(DMPlexTransformApply(tr, dm, &edm)); 4337 PetscCall(DMCopyDisc(dm, edm)); 4338 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4339 PetscCall(DMGetCoordinateDM(edm, &ecdm)); 4340 PetscCall(DMCopyDisc(cdm, ecdm)); 4341 PetscCall(DMPlexTransformCreateDiscLabels(tr, edm)); 4342 PetscCall(DMPlexTransformDestroy(&tr)); 4343 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, edm)); 4344 PetscCall(DMPlexReplace_Internal(dm, &edm)); 4345 } 4346 PetscFunctionReturn(PETSC_SUCCESS); 4347 } 4348 4349 /*@ 4350 DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface 4351 4352 Collective 4353 4354 Input Parameters: 4355 + comm - The communicator for the `DM` object 4356 . tpstype - Type of triply-periodic surface 4357 . extent - Array of length 3 containing number of periods in each direction 4358 . periodic - array of length 3 with periodicity, or `NULL` for non-periodic 4359 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable) 4360 . refinements - Number of factor-of-2 refinements of 2D manifold mesh 4361 . layers - Number of cell layers extruded in normal direction 4362 - thickness - Thickness in normal direction 4363 4364 Output Parameter: 4365 . dm - The `DM` object 4366 4367 Level: beginner 4368 4369 Notes: 4370 This meshes the surface of the Schwarz P or Gyroid surfaces. Schwarz P is the simplest member of the triply-periodic minimal surfaces. 4371 <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries. 4372 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. 4373 Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested. 4374 On each refinement, all vertices are projected to their nearest point on the surface. 4375 This projection could readily be extended to related surfaces. 4376 4377 See {cite}`maskery2018insights` 4378 4379 The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$. 4380 When the mesh is refined, "Face Sets" contain the new vertices (created during refinement). 4381 Use `DMPlexLabelComplete()` to propagate to coarse-level vertices. 4382 4383 Developer Notes: 4384 The Gyroid mesh does not currently mark boundary sets. 4385 4386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()` 4387 @*/ 4388 PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm) 4389 { 4390 PetscFunctionBegin; 4391 PetscCall(DMCreate(comm, dm)); 4392 PetscCall(DMSetType(*dm, DMPLEX)); 4393 PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness)); 4394 PetscFunctionReturn(PETSC_SUCCESS); 4395 } 4396 4397 /*@ 4398 DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d. 4399 4400 Collective 4401 4402 Input Parameters: 4403 + comm - The communicator for the `DM` object 4404 . dim - The dimension 4405 . simplex - Use simplices, or tensor product cells 4406 - R - The radius 4407 4408 Output Parameter: 4409 . dm - The `DM` object 4410 4411 Level: beginner 4412 4413 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 4414 @*/ 4415 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm) 4416 { 4417 PetscFunctionBegin; 4418 PetscAssertPointer(dm, 5); 4419 PetscCall(DMCreate(comm, dm)); 4420 PetscCall(DMSetType(*dm, DMPLEX)); 4421 PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R)); 4422 PetscFunctionReturn(PETSC_SUCCESS); 4423 } 4424 4425 static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R) 4426 { 4427 DM sdm, vol; 4428 DMLabel bdlabel; 4429 const char *prefix; 4430 4431 PetscFunctionBegin; 4432 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm)); 4433 PetscCall(DMSetType(sdm, DMPLEX)); 4434 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 4435 PetscCall(DMSetOptionsPrefix(sdm, prefix)); 4436 PetscCall(DMAppendOptionsPrefix(sdm, "bd_")); 4437 PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE)); 4438 PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R)); 4439 PetscCall(DMSetFromOptions(sdm)); 4440 PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view")); 4441 PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol)); 4442 PetscCall(DMDestroy(&sdm)); 4443 PetscCall(DMPlexReplace_Internal(dm, &vol)); 4444 PetscCall(DMCreateLabel(dm, "marker")); 4445 PetscCall(DMGetLabel(dm, "marker", &bdlabel)); 4446 PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel)); 4447 PetscCall(DMPlexLabelComplete(dm, bdlabel)); 4448 PetscFunctionReturn(PETSC_SUCCESS); 4449 } 4450 4451 /*@ 4452 DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d. 4453 4454 Collective 4455 4456 Input Parameters: 4457 + comm - The communicator for the `DM` object 4458 . dim - The dimension 4459 - R - The radius 4460 4461 Output Parameter: 4462 . dm - The `DM` object 4463 4464 Options Database Key: 4465 . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry 4466 4467 Level: beginner 4468 4469 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 4470 @*/ 4471 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm) 4472 { 4473 PetscFunctionBegin; 4474 PetscCall(DMCreate(comm, dm)); 4475 PetscCall(DMSetType(*dm, DMPLEX)); 4476 PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R)); 4477 PetscFunctionReturn(PETSC_SUCCESS); 4478 } 4479 4480 static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct) 4481 { 4482 PetscFunctionBegin; 4483 switch (ct) { 4484 case DM_POLYTOPE_POINT: { 4485 PetscInt numPoints[1] = {1}; 4486 PetscInt coneSize[1] = {0}; 4487 PetscInt cones[1] = {0}; 4488 PetscInt coneOrientations[1] = {0}; 4489 PetscScalar vertexCoords[1] = {0.0}; 4490 4491 PetscCall(DMSetDimension(rdm, 0)); 4492 PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4493 } break; 4494 case DM_POLYTOPE_SEGMENT: { 4495 PetscInt numPoints[2] = {2, 1}; 4496 PetscInt coneSize[3] = {2, 0, 0}; 4497 PetscInt cones[2] = {1, 2}; 4498 PetscInt coneOrientations[2] = {0, 0}; 4499 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 4500 4501 PetscCall(DMSetDimension(rdm, 1)); 4502 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4503 } break; 4504 case DM_POLYTOPE_POINT_PRISM_TENSOR: { 4505 PetscInt numPoints[2] = {2, 1}; 4506 PetscInt coneSize[3] = {2, 0, 0}; 4507 PetscInt cones[2] = {1, 2}; 4508 PetscInt coneOrientations[2] = {0, 0}; 4509 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 4510 4511 PetscCall(DMSetDimension(rdm, 1)); 4512 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4513 } break; 4514 case DM_POLYTOPE_TRIANGLE: { 4515 PetscInt numPoints[2] = {3, 1}; 4516 PetscInt coneSize[4] = {3, 0, 0, 0}; 4517 PetscInt cones[3] = {1, 2, 3}; 4518 PetscInt coneOrientations[3] = {0, 0, 0}; 4519 PetscScalar vertexCoords[6] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0}; 4520 4521 PetscCall(DMSetDimension(rdm, 2)); 4522 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4523 } break; 4524 case DM_POLYTOPE_QUADRILATERAL: { 4525 PetscInt numPoints[2] = {4, 1}; 4526 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 4527 PetscInt cones[4] = {1, 2, 3, 4}; 4528 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 4529 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0}; 4530 4531 PetscCall(DMSetDimension(rdm, 2)); 4532 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4533 } break; 4534 case DM_POLYTOPE_SEG_PRISM_TENSOR: { 4535 PetscInt numPoints[2] = {4, 1}; 4536 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 4537 PetscInt cones[4] = {1, 2, 3, 4}; 4538 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 4539 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; 4540 4541 PetscCall(DMSetDimension(rdm, 2)); 4542 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4543 } break; 4544 case DM_POLYTOPE_TETRAHEDRON: { 4545 PetscInt numPoints[2] = {4, 1}; 4546 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 4547 PetscInt cones[4] = {1, 2, 3, 4}; 4548 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 4549 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}; 4550 4551 PetscCall(DMSetDimension(rdm, 3)); 4552 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4553 } break; 4554 case DM_POLYTOPE_HEXAHEDRON: { 4555 PetscInt numPoints[2] = {8, 1}; 4556 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 4557 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 4558 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 4559 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}; 4560 4561 PetscCall(DMSetDimension(rdm, 3)); 4562 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4563 } break; 4564 case DM_POLYTOPE_TRI_PRISM: { 4565 PetscInt numPoints[2] = {6, 1}; 4566 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 4567 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 4568 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 4569 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}; 4570 4571 PetscCall(DMSetDimension(rdm, 3)); 4572 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4573 } break; 4574 case DM_POLYTOPE_TRI_PRISM_TENSOR: { 4575 PetscInt numPoints[2] = {6, 1}; 4576 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 4577 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 4578 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 4579 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}; 4580 4581 PetscCall(DMSetDimension(rdm, 3)); 4582 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4583 } break; 4584 case DM_POLYTOPE_QUAD_PRISM_TENSOR: { 4585 PetscInt numPoints[2] = {8, 1}; 4586 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 4587 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 4588 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 4589 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}; 4590 4591 PetscCall(DMSetDimension(rdm, 3)); 4592 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4593 } break; 4594 case DM_POLYTOPE_PYRAMID: { 4595 PetscInt numPoints[2] = {5, 1}; 4596 PetscInt coneSize[6] = {5, 0, 0, 0, 0, 0}; 4597 PetscInt cones[5] = {1, 2, 3, 4, 5}; 4598 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 4599 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}; 4600 4601 PetscCall(DMSetDimension(rdm, 3)); 4602 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4603 } break; 4604 default: 4605 SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]); 4606 } 4607 { 4608 PetscInt Nv, v; 4609 4610 /* Must create the celltype label here so that we do not automatically try to compute the types */ 4611 PetscCall(DMCreateLabel(rdm, "celltype")); 4612 PetscCall(DMPlexSetCellType(rdm, 0, ct)); 4613 PetscCall(DMPlexGetChart(rdm, NULL, &Nv)); 4614 for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT)); 4615 } 4616 PetscCall(DMPlexInterpolateInPlace_Internal(rdm)); 4617 PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct])); 4618 PetscFunctionReturn(PETSC_SUCCESS); 4619 } 4620 4621 /*@ 4622 DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell 4623 4624 Collective 4625 4626 Input Parameters: 4627 + comm - The communicator 4628 - ct - The cell type of the reference cell 4629 4630 Output Parameter: 4631 . refdm - The reference cell 4632 4633 Level: intermediate 4634 4635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()` 4636 @*/ 4637 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm) 4638 { 4639 PetscFunctionBegin; 4640 PetscCall(DMCreate(comm, refdm)); 4641 PetscCall(DMSetType(*refdm, DMPLEX)); 4642 PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct)); 4643 PetscFunctionReturn(PETSC_SUCCESS); 4644 } 4645 4646 static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[]) 4647 { 4648 DM plex; 4649 DMLabel label; 4650 PetscBool hasLabel; 4651 4652 PetscFunctionBegin; 4653 PetscCall(DMHasLabel(dm, name, &hasLabel)); 4654 if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS); 4655 PetscCall(DMCreateLabel(dm, name)); 4656 PetscCall(DMGetLabel(dm, name, &label)); 4657 PetscCall(DMConvert(dm, DMPLEX, &plex)); 4658 PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label)); 4659 PetscCall(DMPlexLabelComplete(plex, label)); 4660 PetscCall(DMDestroy(&plex)); 4661 PetscFunctionReturn(PETSC_SUCCESS); 4662 } 4663 4664 /* 4665 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. 4666 4667 (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0])) 4668 */ 4669 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[]) 4670 { 4671 const PetscReal low = PetscRealPart(constants[0]); 4672 const PetscReal upp = PetscRealPart(constants[1]); 4673 const PetscReal r = PetscRealPart(u[1]); 4674 const PetscReal th = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low); 4675 4676 f0[0] = r * PetscCosReal(th); 4677 f0[1] = r * PetscSinReal(th); 4678 } 4679 4680 // Insert vertices and their joins, marked by depth 4681 static PetscErrorCode ProcessCohesiveLabel_Vertices(DM dm, DMLabel label, DMLabel vlabel, PetscInt val, PetscInt n, const PetscInt vertices[]) 4682 { 4683 PetscFunctionBegin; 4684 PetscCall(DMPlexMarkSubmesh_Interpolated(dm, vlabel, val, PETSC_FALSE, PETSC_FALSE, label, NULL)); 4685 PetscFunctionReturn(PETSC_SUCCESS); 4686 } 4687 4688 // Insert faces and their closures, marked by depth 4689 static PetscErrorCode ProcessCohesiveLabel_Faces(DM dm, DMLabel label, PetscInt n, const PetscInt faces[]) 4690 { 4691 PetscFunctionBegin; 4692 for (PetscInt p = 0; p < n; ++p) { 4693 const PetscInt point = faces[p]; 4694 PetscInt *closure = NULL; 4695 PetscInt clSize, pdepth; 4696 4697 PetscCall(DMPlexGetPointDepth(dm, point, &pdepth)); 4698 PetscCall(DMLabelSetValue(label, point, pdepth)); 4699 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4700 for (PetscInt cl = 0; cl < clSize * 2; cl += 2) { 4701 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth)); 4702 PetscCall(DMLabelSetValue(label, closure[cl], pdepth)); 4703 } 4704 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4705 } 4706 PetscFunctionReturn(PETSC_SUCCESS); 4707 } 4708 4709 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg); 4710 4711 const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL}; 4712 4713 static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems PetscOptionsObject, PetscBool *useCoordSpace, DM dm) 4714 { 4715 DMPlexShape shape = DM_SHAPE_BOX; 4716 DMPolytopeType cell = DM_POLYTOPE_TRIANGLE; 4717 PetscInt dim = 2; 4718 PetscBool simplex = PETSC_TRUE, interpolate = PETSC_TRUE, orient = PETSC_FALSE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE; 4719 PetscBool flg, flg2, fflg, strflg, bdfflg, nameflg; 4720 MPI_Comm comm; 4721 char filename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 4722 char bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 4723 char plexname[PETSC_MAX_PATH_LEN] = ""; 4724 const char *option; 4725 4726 PetscFunctionBegin; 4727 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 4728 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4729 /* TODO Turn this into a registration interface */ 4730 PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg)); 4731 PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg)); 4732 PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg)); 4733 PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg)); 4734 PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL)); 4735 PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL)); 4736 PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg)); 4737 PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0)); 4738 PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg)); 4739 PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg)); 4740 PetscCall(PetscOptionsBool("-dm_plex_orient", "Orient the constructed mesh", "DMPlexOrient", orient, &orient, &flg)); 4741 PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg)); 4742 PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2)); 4743 if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure)); 4744 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_adj", "Debug output level all adjacency computations", "", 0, &((DM_Plex *)dm->data)->printAdj, NULL, 0)); 4745 4746 switch (cell) { 4747 case DM_POLYTOPE_POINT: 4748 case DM_POLYTOPE_SEGMENT: 4749 case DM_POLYTOPE_POINT_PRISM_TENSOR: 4750 case DM_POLYTOPE_TRIANGLE: 4751 case DM_POLYTOPE_QUADRILATERAL: 4752 case DM_POLYTOPE_TETRAHEDRON: 4753 case DM_POLYTOPE_HEXAHEDRON: 4754 *useCoordSpace = PETSC_TRUE; 4755 break; 4756 default: 4757 *useCoordSpace = PETSC_FALSE; 4758 break; 4759 } 4760 4761 if (fflg) { 4762 DM dmnew; 4763 const char *name; 4764 4765 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 4766 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, nameflg ? plexname : name, interpolate, &dmnew)); 4767 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4768 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4769 } else if (refDomain) { 4770 PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell)); 4771 } else if (bdfflg) { 4772 DM bdm, dmnew; 4773 const char *name; 4774 4775 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 4776 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, nameflg ? plexname : name, interpolate, &bdm)); 4777 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_")); 4778 PetscCall(DMSetFromOptions(bdm)); 4779 PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew)); 4780 PetscCall(DMDestroy(&bdm)); 4781 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4782 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4783 } else if (strflg) { 4784 DM dmnew; 4785 PetscViewer viewer; 4786 const char *contents; 4787 char *strname; 4788 char tmpdir[PETSC_MAX_PATH_LEN]; 4789 char tmpfilename[PETSC_MAX_PATH_LEN]; 4790 char name[PETSC_MAX_PATH_LEN]; 4791 MPI_Comm comm; 4792 PetscMPIInt rank; 4793 4794 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4795 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 4796 PetscCall(PetscStrchr(filename, ':', &strname)); 4797 PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename); 4798 strname[0] = '\0'; 4799 ++strname; 4800 PetscCall(PetscDLSym(NULL, strname, (void **)&contents)); 4801 PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname); 4802 PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN)); 4803 PetscCall(PetscStrlcat(tmpdir, "/meshXXXXXX", PETSC_MAX_PATH_LEN)); 4804 PetscCall(PetscMkdtemp(tmpdir)); 4805 PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh.%s", tmpdir, filename)); 4806 PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer)); 4807 PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents)); 4808 PetscCall(PetscViewerDestroy(&viewer)); 4809 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew)); 4810 PetscCall(PetscRMTree(tmpdir)); 4811 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname)); 4812 PetscCall(PetscObjectSetName((PetscObject)dm, name)); 4813 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4814 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4815 } else { 4816 PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape])); 4817 switch (shape) { 4818 case DM_SHAPE_BOX: 4819 case DM_SHAPE_ZBOX: 4820 case DM_SHAPE_ANNULUS: { 4821 PetscInt faces[3] = {0, 0, 0}; 4822 PetscReal lower[3] = {0, 0, 0}; 4823 PetscReal upper[3] = {1, 1, 1}; 4824 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4825 PetscBool isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE; 4826 PetscInt i, n; 4827 4828 n = dim; 4829 for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim); 4830 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4831 n = 3; 4832 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4833 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4834 n = 3; 4835 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4836 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4837 n = 3; 4838 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4839 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4840 4841 PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented"); 4842 if (isAnnular) 4843 for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC; 4844 4845 switch (cell) { 4846 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4847 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt)); 4848 if (!interpolate) { 4849 DM udm; 4850 4851 PetscCall(DMPlexUninterpolate(dm, &udm)); 4852 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4853 } 4854 break; 4855 default: 4856 PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate)); 4857 break; 4858 } 4859 if (isAnnular) { 4860 DM cdm; 4861 PetscDS cds; 4862 PetscScalar bounds[2] = {lower[0], upper[0]}; 4863 4864 // Fix coordinates for annular region 4865 PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 4866 PetscCall(DMSetCellCoordinatesLocal(dm, NULL)); 4867 PetscCall(DMSetCellCoordinates(dm, NULL)); 4868 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 4869 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4870 PetscCall(DMGetDS(cdm, &cds)); 4871 PetscCall(PetscDSSetConstants(cds, 2, bounds)); 4872 PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus)); 4873 } 4874 } break; 4875 case DM_SHAPE_BOX_SURFACE: { 4876 PetscInt faces[3] = {0, 0, 0}; 4877 PetscReal lower[3] = {0, 0, 0}; 4878 PetscReal upper[3] = {1, 1, 1}; 4879 PetscInt i, n; 4880 4881 n = dim + 1; 4882 for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1)); 4883 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4884 n = 3; 4885 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4886 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); 4887 n = 3; 4888 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4889 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); 4890 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate)); 4891 } break; 4892 case DM_SHAPE_SPHERE: { 4893 PetscReal R = 1.0; 4894 4895 PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg)); 4896 PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R)); 4897 } break; 4898 case DM_SHAPE_BALL: { 4899 PetscReal R = 1.0; 4900 4901 PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg)); 4902 PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R)); 4903 } break; 4904 case DM_SHAPE_CYLINDER: { 4905 DMBoundaryType bdt = DM_BOUNDARY_NONE; 4906 PetscInt Nw = 6; 4907 PetscInt Nr = 0; 4908 4909 PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL)); 4910 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL)); 4911 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_refine", "Number of refinements before projection", "", Nr, &Nr, NULL)); 4912 switch (cell) { 4913 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4914 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate)); 4915 break; 4916 default: 4917 PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt, Nr)); 4918 break; 4919 } 4920 } break; 4921 case DM_SHAPE_SCHWARZ_P: // fallthrough 4922 case DM_SHAPE_GYROID: { 4923 PetscInt extent[3] = {1, 1, 1}, refine = 0, layers = 0, three; 4924 PetscReal thickness = 0.; 4925 DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4926 DMPlexTPSType tps_type = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID; 4927 PetscBool tps_distribute; 4928 PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL)); 4929 PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL)); 4930 PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL)); 4931 PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL)); 4932 PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL)); 4933 PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute)); 4934 PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL)); 4935 PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness)); 4936 } break; 4937 case DM_SHAPE_DOUBLET: { 4938 DM dmnew; 4939 PetscReal rl = 0.0; 4940 4941 PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL)); 4942 PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew)); 4943 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4944 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4945 } break; 4946 case DM_SHAPE_HYPERCUBIC: { 4947 PetscInt *edges, overlap = 1; 4948 PetscReal *lower, *upper; 4949 DMBoundaryType *bdt; 4950 PetscInt n, d; 4951 4952 *useCoordSpace = PETSC_FALSE; 4953 PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt)); 4954 for (d = 0; d < dim; ++d) { 4955 edges[d] = 1; 4956 lower[d] = 0.; 4957 upper[d] = 1.; 4958 bdt[d] = DM_BOUNDARY_PERIODIC; 4959 } 4960 n = dim; 4961 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg)); 4962 n = dim; 4963 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4964 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4965 n = dim; 4966 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4967 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4968 n = dim; 4969 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4970 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4971 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", overlap, &overlap, NULL, 0)); 4972 PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, overlap, bdt)); 4973 PetscCall(PetscFree4(edges, lower, upper, bdt)); 4974 } break; 4975 default: 4976 SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]); 4977 } 4978 } 4979 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4980 if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname)); 4981 if (orient) PetscCall(DMPlexOrient(dm)); 4982 // Allow label creation 4983 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg)); 4984 if (flg) { 4985 DMLabel label; 4986 PetscInt points[1024], n = 1024; 4987 char fulloption[PETSC_MAX_PATH_LEN]; 4988 const char *name = &option[14]; 4989 4990 PetscCall(DMCreateLabel(dm, name)); 4991 PetscCall(DMGetLabel(dm, name, &label)); 4992 fulloption[0] = '-'; 4993 fulloption[1] = 0; 4994 PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN)); 4995 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL)); 4996 for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1)); 4997 } 4998 // Allow cohesive label creation 4999 // Faces are input, completed, and all points are marked with their depth 5000 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg)); 5001 if (flg) { 5002 DMLabel label; 5003 PetscInt points[1024], n, pStart, pEnd, Nl = 1; 5004 PetscBool noCreate = PETSC_FALSE; 5005 char fulloption[PETSC_MAX_PATH_LEN]; 5006 char name[PETSC_MAX_PATH_LEN]; 5007 size_t len; 5008 5009 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5010 PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN)); 5011 PetscCall(PetscStrlen(name, &len)); 5012 if (name[len - 1] == '0') Nl = 10; 5013 for (PetscInt l = 0; l < Nl; ++l) { 5014 if (l > 0) name[len - 1] = (char)('0' + l); 5015 fulloption[0] = 0; 5016 PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32)); 5017 PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32)); 5018 n = 1024; 5019 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg)); 5020 if (!flg) break; 5021 PetscCall(DMHasLabel(dm, name, &noCreate)); 5022 if (noCreate) { 5023 DMLabel inlabel; 5024 IS pointIS; 5025 const PetscInt *lpoints; 5026 PetscInt pdep, ln, inval = points[0]; 5027 char newname[PETSC_MAX_PATH_LEN]; 5028 5029 PetscCheck(n == 1, comm, PETSC_ERR_ARG_WRONG, "Must specify a label value with this option"); 5030 PetscCall(DMGetLabel(dm, name, &inlabel)); 5031 PetscCall(DMLabelGetStratumIS(inlabel, inval, &pointIS)); 5032 PetscCall(ISGetLocalSize(pointIS, &ln)); 5033 PetscCall(ISGetIndices(pointIS, &lpoints)); 5034 PetscCall(DMPlexGetPointDepth(dm, lpoints[0], &pdep)); 5035 PetscCall(PetscSNPrintf(newname, PETSC_MAX_PATH_LEN, "%s%" PetscInt_FMT, name, points[0])); 5036 PetscCall(DMCreateLabel(dm, newname)); 5037 PetscCall(DMGetLabel(dm, newname, &label)); 5038 if (!pdep) PetscCall(ProcessCohesiveLabel_Vertices(dm, label, inlabel, inval, ln, lpoints)); 5039 else PetscCall(ProcessCohesiveLabel_Faces(dm, label, ln, lpoints)); 5040 PetscCall(ISRestoreIndices(pointIS, &lpoints)); 5041 PetscCall(ISDestroy(&pointIS)); 5042 } else { 5043 PetscCall(DMCreateLabel(dm, name)); 5044 PetscCall(DMGetLabel(dm, name, &label)); 5045 if (pStart >= pEnd) n = 0; 5046 PetscCall(ProcessCohesiveLabel_Faces(dm, label, n, points)); 5047 } 5048 PetscCall(DMPlexOrientLabel(dm, label)); 5049 PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL)); 5050 } 5051 } 5052 PetscCall(DMViewFromOptions(dm, NULL, "-created_dm_view")); 5053 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 5054 PetscFunctionReturn(PETSC_SUCCESS); 5055 } 5056 5057 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems PetscOptionsObject) 5058 { 5059 DM_Plex *mesh = (DM_Plex *)dm->data; 5060 PetscBool flg, flg2; 5061 char bdLabel[PETSC_MAX_PATH_LEN]; 5062 char method[PETSC_MAX_PATH_LEN]; 5063 5064 PetscFunctionBegin; 5065 /* Handle viewing */ 5066 PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL)); 5067 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0)); 5068 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0)); 5069 PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL)); 5070 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0)); 5071 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0)); 5072 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_project", "Debug output level all projection computations", "DMPlexProject", 0, &mesh->printProject, NULL, 0)); 5073 PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg)); 5074 if (flg) PetscCall(PetscLogDefaultBegin()); 5075 // Interpolation 5076 PetscCall(PetscOptionsBool("-dm_plex_interpolate_prefer_tensor", "When different orderings exist, prefer the tensor order", "DMPlexSetInterpolationPreferTensor", mesh->interpolatePreferTensor, &mesh->interpolatePreferTensor, NULL)); 5077 /* Labeling */ 5078 PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg)); 5079 if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel)); 5080 /* Point Location */ 5081 PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL)); 5082 /* Partitioning and distribution */ 5083 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL)); 5084 /* Reordering */ 5085 PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg)); 5086 if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE)); 5087 PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg)); 5088 if (flg) PetscCall(DMReorderSectionSetType(dm, method)); 5089 /* Generation and remeshing */ 5090 PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL)); 5091 PetscCall(PetscOptionsBool("-dm_plex_save_transform", "Save the transform producing this mesh", "DMAdapt", PETSC_FALSE, &mesh->saveTransform, NULL)); 5092 /* Projection behavior */ 5093 PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0)); 5094 PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL)); 5095 /* Checking structure */ 5096 { 5097 PetscBool all = PETSC_FALSE; 5098 5099 PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL)); 5100 if (all) { 5101 PetscCall(DMPlexCheck(dm)); 5102 } else { 5103 PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2)); 5104 if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm)); 5105 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)); 5106 if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0)); 5107 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)); 5108 if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0)); 5109 PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2)); 5110 if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm)); 5111 PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2)); 5112 if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 5113 PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2)); 5114 if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm)); 5115 } 5116 PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2)); 5117 if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE)); 5118 } 5119 { 5120 PetscReal scale = 1.0; 5121 5122 PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg)); 5123 if (flg) { 5124 Vec coordinates, coordinatesLocal; 5125 5126 PetscCall(DMGetCoordinates(dm, &coordinates)); 5127 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 5128 PetscCall(VecScale(coordinates, scale)); 5129 PetscCall(VecScale(coordinatesLocal, scale)); 5130 } 5131 } 5132 PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner)); 5133 PetscFunctionReturn(PETSC_SUCCESS); 5134 } 5135 5136 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems PetscOptionsObject, PetscInt *overlap) 5137 { 5138 PetscInt numOvLabels = 16, numOvExLabels = 16; 5139 char *ovLabelNames[16], *ovExLabelNames[16]; 5140 PetscInt numOvValues = 16, numOvExValues = 16, l; 5141 PetscBool flg; 5142 5143 PetscFunctionBegin; 5144 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0)); 5145 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg)); 5146 if (!flg) numOvLabels = 0; 5147 if (numOvLabels) { 5148 ((DM_Plex *)dm->data)->numOvLabels = numOvLabels; 5149 for (l = 0; l < numOvLabels; ++l) { 5150 PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l])); 5151 PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]); 5152 PetscCall(PetscFree(ovLabelNames[l])); 5153 } 5154 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg)); 5155 if (!flg) numOvValues = 0; 5156 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); 5157 5158 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg)); 5159 if (!flg) numOvExLabels = 0; 5160 ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels; 5161 for (l = 0; l < numOvExLabels; ++l) { 5162 PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l])); 5163 PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]); 5164 PetscCall(PetscFree(ovExLabelNames[l])); 5165 } 5166 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg)); 5167 if (!flg) numOvExValues = 0; 5168 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); 5169 } 5170 PetscFunctionReturn(PETSC_SUCCESS); 5171 } 5172 5173 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems PetscOptionsObject) 5174 { 5175 PetscFunctionList ordlist; 5176 char oname[256]; 5177 char sublabelname[PETSC_MAX_PATH_LEN] = ""; 5178 DMReorderDefaultFlag reorder; 5179 PetscReal volume = -1.0; 5180 PetscInt prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim; 5181 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; 5182 5183 PetscFunctionBegin; 5184 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options"); 5185 if (dm->cloneOpts) goto non_refine; 5186 /* Handle automatic creation */ 5187 PetscCall(DMGetDimension(dm, &dim)); 5188 if (dim < 0) PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm)); 5189 PetscCall(DMGetDimension(dm, &dim)); 5190 /* Handle interpolation before distribution */ 5191 PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg)); 5192 if (flg) { 5193 DMPlexInterpolatedFlag interpolated; 5194 5195 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 5196 if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) { 5197 DM udm; 5198 5199 PetscCall(DMPlexUninterpolate(dm, &udm)); 5200 PetscCall(DMPlexReplace_Internal(dm, &udm)); 5201 } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) { 5202 DM idm; 5203 5204 PetscCall(DMPlexInterpolate(dm, &idm)); 5205 PetscCall(DMPlexReplace_Internal(dm, &idm)); 5206 } 5207 } 5208 // Handle submesh selection before distribution 5209 PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg)); 5210 if (flg) { 5211 DM subdm; 5212 DMLabel label; 5213 IS valueIS, pointIS; 5214 const PetscInt *values, *points; 5215 PetscBool markedFaces = PETSC_FALSE; 5216 PetscInt Nv, value, Np; 5217 5218 PetscCall(DMGetLabel(dm, sublabelname, &label)); 5219 PetscCall(DMLabelGetNumValues(label, &Nv)); 5220 PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv); 5221 PetscCall(DMLabelGetValueIS(label, &valueIS)); 5222 PetscCall(ISGetIndices(valueIS, &values)); 5223 value = values[0]; 5224 PetscCall(ISRestoreIndices(valueIS, &values)); 5225 PetscCall(ISDestroy(&valueIS)); 5226 PetscCall(DMLabelGetStratumSize(label, value, &Np)); 5227 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 5228 PetscCall(ISGetIndices(pointIS, &points)); 5229 for (PetscInt p = 0; p < Np; ++p) { 5230 PetscInt pdepth; 5231 5232 PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth)); 5233 if (pdepth) { 5234 markedFaces = PETSC_TRUE; 5235 break; 5236 } 5237 } 5238 PetscCall(ISRestoreIndices(pointIS, &points)); 5239 PetscCall(ISDestroy(&pointIS)); 5240 PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm)); 5241 PetscCall(DMPlexReplace_Internal(dm, &subdm)); 5242 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5243 } 5244 /* Handle DMPlex refinement before distribution */ 5245 PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig)); 5246 PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0)); 5247 PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 5248 PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg)); 5249 if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform)); 5250 PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg)); 5251 if (flg) { 5252 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE)); 5253 PetscCall(DMPlexSetRefinementLimit(dm, volume)); 5254 prerefine = PetscMax(prerefine, 1); 5255 } 5256 if (prerefine) PetscCall(DMLocalizeCoordinates(dm)); 5257 for (r = 0; r < prerefine; ++r) { 5258 DM rdm; 5259 PetscPointFunc coordFunc; 5260 5261 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 5262 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5263 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 5264 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 5265 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5266 if (coordFunc && remap) { 5267 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 5268 PetscCall(DMPlexSetCoordinateMap(dm, coordFunc)); 5269 } 5270 } 5271 PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig)); 5272 /* Handle DMPlex extrusion before distribution */ 5273 PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0)); 5274 if (extLayers) { 5275 DM edm; 5276 5277 PetscCall(DMExtrude(dm, extLayers, &edm)); 5278 PetscCall(DMPlexReplace_Internal(dm, &edm)); 5279 PetscCall(DMPlexSetCoordinateMap(dm, NULL)); 5280 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5281 extLayers = 0; 5282 PetscCall(DMGetDimension(dm, &dim)); 5283 } 5284 /* Handle DMPlex reordering before distribution */ 5285 PetscCall(DMPlexReorderGetDefault(dm, &reorder)); 5286 PetscCall(MatGetOrderingList(&ordlist)); 5287 PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname))); 5288 PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg)); 5289 if (reorder == DM_REORDER_DEFAULT_TRUE || flg) { 5290 DM pdm; 5291 IS perm; 5292 5293 PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm)); 5294 PetscCall(DMPlexPermute(dm, perm, &pdm)); 5295 PetscCall(ISDestroy(&perm)); 5296 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 5297 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5298 } 5299 /* Handle DMPlex distribution */ 5300 PetscCall(DMPlexDistributeGetDefault(dm, &distribute)); 5301 PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL)); 5302 PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL)); 5303 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 5304 if (distribute) { 5305 DM pdm = NULL; 5306 PetscPartitioner part; 5307 PetscSF sfMigration; 5308 PetscBool use_partition_balance; 5309 5310 PetscCall(DMPlexGetPartitioner(dm, &part)); 5311 PetscCall(PetscPartitionerSetFromOptions(part)); 5312 PetscCall(DMPlexGetPartitionBalance(dm, &use_partition_balance)); 5313 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", use_partition_balance, &use_partition_balance, &flg)); 5314 if (flg) PetscCall(DMPlexSetPartitionBalance(dm, use_partition_balance)); 5315 PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm)); 5316 if (pdm) { 5317 // Delete the local section to force the existing one to be rebuilt with the distributed DM 5318 PetscCall(DMSetLocalSection(dm, pdm->localSection)); 5319 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 5320 } 5321 if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration)); 5322 PetscCall(PetscSFDestroy(&sfMigration)); 5323 } 5324 5325 { 5326 PetscBool useBoxLabel = PETSC_FALSE; 5327 PetscCall(PetscOptionsBool("-dm_plex_box_label", "Create 'Face Sets' assuming boundary faces align with cartesian directions", "DMCreate", useBoxLabel, &useBoxLabel, NULL)); 5328 if (useBoxLabel) { 5329 PetscInt n = 3; 5330 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 5331 5332 PetscCall(PetscOptionsEnumArray("-dm_plex_box_label_bd", "Boundary type for each dimension when using -dm_plex_box_label", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 5333 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); 5334 PetscCall(DMPlexSetBoxLabel_Internal(dm, bdt)); 5335 } 5336 } 5337 /* Must check CEED options before creating function space for coordinates */ 5338 { 5339 PetscBool useCeed = PETSC_FALSE, flg; 5340 5341 PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg)); 5342 if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed)); 5343 } 5344 /* Create coordinate space */ 5345 PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, NULL)); 5346 if (coordSpace) { 5347 PetscInt degree = 1, deg; 5348 PetscInt height = 0; 5349 DM cdm; 5350 PetscBool localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE; 5351 5352 PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, °ree, NULL)); 5353 PetscCall(DMGetCoordinateDegree_Internal(dm, °)); 5354 if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, NULL)); 5355 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5356 if (!coordSpace) { 5357 PetscDS cds; 5358 PetscObject obj; 5359 PetscClassId id; 5360 5361 PetscCall(DMGetDS(cdm, &cds)); 5362 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 5363 PetscCall(PetscObjectGetClassId(obj, &id)); 5364 if (id == PETSCFE_CLASSID) { 5365 PetscContainer dummy; 5366 5367 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy)); 5368 PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates")); 5369 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy)); 5370 PetscCall(PetscContainerDestroy(&dummy)); 5371 PetscCall(DMClearDS(cdm)); 5372 } 5373 PetscCall(DMPlexSetCoordinateMap(dm, NULL)); 5374 } 5375 PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL)); 5376 PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg)); 5377 if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize)); 5378 PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg)); 5379 if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height)); 5380 if (localize) PetscCall(DMLocalizeCoordinates(dm)); 5381 } 5382 /* Handle DMPlex refinement */ 5383 remap = PETSC_TRUE; 5384 PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0)); 5385 PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 5386 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0)); 5387 if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 5388 if (refine && isHierarchy) { 5389 DM *dms, coarseDM; 5390 5391 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 5392 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 5393 PetscCall(PetscMalloc1(refine, &dms)); 5394 PetscCall(DMRefineHierarchy(dm, refine, dms)); 5395 /* Total hack since we do not pass in a pointer */ 5396 PetscCall(DMPlexSwap_Static(dm, dms[refine - 1])); 5397 if (refine == 1) { 5398 PetscCall(DMSetCoarseDM(dm, dms[0])); 5399 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 5400 } else { 5401 PetscCall(DMSetCoarseDM(dm, dms[refine - 2])); 5402 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 5403 PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1])); 5404 PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE)); 5405 } 5406 PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM)); 5407 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 5408 /* Free DMs */ 5409 for (r = 0; r < refine; ++r) { 5410 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 5411 PetscCall(DMDestroy(&dms[r])); 5412 } 5413 PetscCall(PetscFree(dms)); 5414 } else { 5415 for (r = 0; r < refine; ++r) { 5416 DM rdm; 5417 PetscPointFunc coordFunc; 5418 5419 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 5420 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5421 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 5422 /* Total hack since we do not pass in a pointer */ 5423 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 5424 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5425 if (coordFunc && remap) { 5426 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 5427 PetscCall(DMPlexSetCoordinateMap(dm, coordFunc)); 5428 } 5429 } 5430 } 5431 /* Handle DMPlex coarsening */ 5432 PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0)); 5433 PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0)); 5434 if (coarsen && isHierarchy) { 5435 DM *dms; 5436 5437 PetscCall(PetscMalloc1(coarsen, &dms)); 5438 PetscCall(DMCoarsenHierarchy(dm, coarsen, dms)); 5439 /* Free DMs */ 5440 for (r = 0; r < coarsen; ++r) { 5441 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 5442 PetscCall(DMDestroy(&dms[r])); 5443 } 5444 PetscCall(PetscFree(dms)); 5445 } else { 5446 for (r = 0; r < coarsen; ++r) { 5447 DM cdm; 5448 PetscPointFunc coordFunc; 5449 5450 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 5451 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5452 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm)); 5453 /* Total hack since we do not pass in a pointer */ 5454 PetscCall(DMPlexReplace_Internal(dm, &cdm)); 5455 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5456 if (coordFunc) { 5457 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 5458 PetscCall(DMPlexSetCoordinateMap(dm, coordFunc)); 5459 } 5460 } 5461 } 5462 // Handle coordinate remapping 5463 remap = PETSC_FALSE; 5464 PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL)); 5465 if (remap) { 5466 DMPlexCoordMap map = DM_COORD_MAP_NONE; 5467 PetscPointFunc mapFunc = NULL; 5468 PetscScalar params[16]; 5469 PetscInt Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim; 5470 MPI_Comm comm; 5471 5472 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5473 PetscCall(DMGetCoordinateDim(dm, &cdim)); 5474 PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg)); 5475 if (!flg) Np = 0; 5476 // TODO Allow user to pass a map function by name 5477 PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg)); 5478 if (flg) { 5479 switch (map) { 5480 case DM_COORD_MAP_NONE: 5481 mapFunc = coordMap_identity; 5482 break; 5483 case DM_COORD_MAP_SHEAR: 5484 mapFunc = coordMap_shear; 5485 if (!Np) { 5486 Np = cdim + 1; 5487 params[0] = 0; 5488 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 5489 } 5490 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); 5491 break; 5492 case DM_COORD_MAP_FLARE: 5493 mapFunc = coordMap_flare; 5494 if (!Np) { 5495 Np = cdim + 1; 5496 params[0] = 0; 5497 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 5498 } 5499 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); 5500 break; 5501 case DM_COORD_MAP_ANNULUS: 5502 mapFunc = coordMap_annulus; 5503 if (!Np) { 5504 Np = 2; 5505 params[0] = 1.; 5506 params[1] = 2.; 5507 } 5508 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 5509 break; 5510 case DM_COORD_MAP_SHELL: 5511 mapFunc = coordMap_shell; 5512 if (!Np) { 5513 Np = 2; 5514 params[0] = 1.; 5515 params[1] = 2.; 5516 } 5517 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 5518 break; 5519 case DM_COORD_MAP_SINUSOID: 5520 mapFunc = coordMap_sinusoid; 5521 if (!Np) { 5522 Np = 3; 5523 params[0] = 1.; 5524 params[1] = 1.; 5525 params[2] = 1.; 5526 } 5527 PetscCheck(Np == 3, comm, PETSC_ERR_ARG_WRONG, "The sinusoidal coordinate map must have 3 parameters, not %" PetscInt_FMT, Np); 5528 break; 5529 default: 5530 mapFunc = coordMap_identity; 5531 } 5532 } 5533 if (Np) { 5534 DM cdm; 5535 PetscDS cds; 5536 5537 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5538 PetscCall(DMGetDS(cdm, &cds)); 5539 PetscCall(PetscDSSetConstants(cds, Np, params)); 5540 } 5541 PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc)); 5542 } 5543 /* Handle ghost cells */ 5544 PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL)); 5545 if (ghostCells) { 5546 DM gdm; 5547 char lname[PETSC_MAX_PATH_LEN]; 5548 5549 lname[0] = '\0'; 5550 PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg)); 5551 PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm)); 5552 PetscCall(DMPlexReplace_Internal(dm, &gdm)); 5553 } 5554 /* Handle 1D order */ 5555 if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) { 5556 DM cdm, rdm; 5557 PetscDS cds; 5558 PetscObject obj; 5559 PetscClassId id = PETSC_OBJECT_CLASSID; 5560 IS perm; 5561 PetscInt Nf; 5562 PetscBool distributed; 5563 5564 PetscCall(DMPlexIsDistributed(dm, &distributed)); 5565 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5566 PetscCall(DMGetDS(cdm, &cds)); 5567 PetscCall(PetscDSGetNumFields(cds, &Nf)); 5568 if (Nf) { 5569 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 5570 PetscCall(PetscObjectGetClassId(obj, &id)); 5571 } 5572 if (!distributed && id != PETSCFE_CLASSID) { 5573 PetscCall(DMPlexGetOrdering1D(dm, &perm)); 5574 PetscCall(DMPlexPermute(dm, perm, &rdm)); 5575 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 5576 PetscCall(ISDestroy(&perm)); 5577 } 5578 } 5579 /* Handle */ 5580 non_refine: 5581 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5582 char *phases[16]; 5583 PetscInt Nphases = 16; 5584 PetscCall(PetscOptionsStringArray("-dm_plex_option_phases", "Option phase prefixes", "DMSetFromOptions", phases, &Nphases, &flg)); 5585 PetscOptionsHeadEnd(); 5586 5587 // Phases 5588 if (flg) { 5589 DM cdm; 5590 char *oldPrefix, *oldCoordPrefix; 5591 const char *tmp; 5592 5593 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5594 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &tmp)); 5595 PetscCall(PetscStrallocpy(tmp, &oldPrefix)); 5596 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)cdm, &tmp)); 5597 PetscCall(PetscStrallocpy(tmp, &oldCoordPrefix)); 5598 for (PetscInt ph = 0; ph < Nphases; ++ph) { 5599 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, phases[ph])); 5600 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)cdm, phases[ph])); 5601 PetscCall(PetscInfo(dm, "Options phase %s for DM %s\n", phases[ph], dm->hdr.name)); 5602 PetscCall(DMSetFromOptions(dm)); 5603 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix)); 5604 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5605 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)cdm, oldCoordPrefix)); 5606 PetscCall(PetscFree(phases[ph])); 5607 } 5608 PetscCall(PetscFree(oldPrefix)); 5609 PetscCall(PetscFree(oldCoordPrefix)); 5610 } 5611 PetscFunctionReturn(PETSC_SUCCESS); 5612 } 5613 5614 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec) 5615 { 5616 PetscFunctionBegin; 5617 PetscCall(DMCreateGlobalVector_Section_Private(dm, vec)); 5618 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 5619 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex)); 5620 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native)); 5621 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex)); 5622 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native)); 5623 PetscFunctionReturn(PETSC_SUCCESS); 5624 } 5625 5626 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec) 5627 { 5628 PetscFunctionBegin; 5629 PetscCall(DMCreateLocalVector_Section_Private(dm, vec)); 5630 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local)); 5631 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local)); 5632 PetscFunctionReturn(PETSC_SUCCESS); 5633 } 5634 5635 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 5636 { 5637 PetscInt depth, d; 5638 5639 PetscFunctionBegin; 5640 PetscCall(DMPlexGetDepth(dm, &depth)); 5641 if (depth == 1) { 5642 PetscCall(DMGetDimension(dm, &d)); 5643 if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 5644 else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd)); 5645 else { 5646 *pStart = 0; 5647 *pEnd = 0; 5648 } 5649 } else { 5650 PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 5651 } 5652 PetscFunctionReturn(PETSC_SUCCESS); 5653 } 5654 5655 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 5656 { 5657 PetscSF sf; 5658 PetscMPIInt niranks, njranks; 5659 PetscInt n; 5660 const PetscMPIInt *iranks, *jranks; 5661 DM_Plex *data = (DM_Plex *)dm->data; 5662 5663 PetscFunctionBegin; 5664 PetscCall(DMGetPointSF(dm, &sf)); 5665 if (!data->neighbors) { 5666 PetscCall(PetscSFSetUp(sf)); 5667 PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL)); 5668 PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL)); 5669 PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors)); 5670 PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks)); 5671 PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks)); 5672 n = njranks + niranks; 5673 PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1)); 5674 /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */ 5675 PetscCall(PetscMPIIntCast(n, data->neighbors)); 5676 } 5677 if (nranks) *nranks = data->neighbors[0]; 5678 if (ranks) { 5679 if (data->neighbors[0]) *ranks = data->neighbors + 1; 5680 else *ranks = NULL; 5681 } 5682 PetscFunctionReturn(PETSC_SUCCESS); 5683 } 5684 5685 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec); 5686 5687 static PetscErrorCode DMInitialize_Plex(DM dm) 5688 { 5689 PetscFunctionBegin; 5690 dm->ops->view = DMView_Plex; 5691 dm->ops->load = DMLoad_Plex; 5692 dm->ops->setfromoptions = DMSetFromOptions_Plex; 5693 dm->ops->clone = DMClone_Plex; 5694 dm->ops->setup = DMSetUp_Plex; 5695 dm->ops->createlocalsection = DMCreateLocalSection_Plex; 5696 dm->ops->createsectionpermutation = DMCreateSectionPermutation_Plex; 5697 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_Plex; 5698 dm->ops->createglobalvector = DMCreateGlobalVector_Plex; 5699 dm->ops->createlocalvector = DMCreateLocalVector_Plex; 5700 dm->ops->getlocaltoglobalmapping = NULL; 5701 dm->ops->createfieldis = NULL; 5702 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Plex; 5703 dm->ops->createcoordinatefield = DMCreateCoordinateField_Plex; 5704 dm->ops->getcoloring = NULL; 5705 dm->ops->creatematrix = DMCreateMatrix_Plex; 5706 dm->ops->createinterpolation = DMCreateInterpolation_Plex; 5707 dm->ops->createmassmatrix = DMCreateMassMatrix_Plex; 5708 dm->ops->createmassmatrixlumped = DMCreateMassMatrixLumped_Plex; 5709 dm->ops->createinjection = DMCreateInjection_Plex; 5710 dm->ops->refine = DMRefine_Plex; 5711 dm->ops->coarsen = DMCoarsen_Plex; 5712 dm->ops->refinehierarchy = DMRefineHierarchy_Plex; 5713 dm->ops->coarsenhierarchy = DMCoarsenHierarchy_Plex; 5714 dm->ops->extrude = DMExtrude_Plex; 5715 dm->ops->globaltolocalbegin = NULL; 5716 dm->ops->globaltolocalend = NULL; 5717 dm->ops->localtoglobalbegin = NULL; 5718 dm->ops->localtoglobalend = NULL; 5719 dm->ops->destroy = DMDestroy_Plex; 5720 dm->ops->createsubdm = DMCreateSubDM_Plex; 5721 dm->ops->createsuperdm = DMCreateSuperDM_Plex; 5722 dm->ops->getdimpoints = DMGetDimPoints_Plex; 5723 dm->ops->locatepoints = DMLocatePoints_Plex; 5724 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_Plex; 5725 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex; 5726 dm->ops->projectfieldlocal = DMProjectFieldLocal_Plex; 5727 dm->ops->projectfieldlabellocal = DMProjectFieldLabelLocal_Plex; 5728 dm->ops->projectbdfieldlabellocal = DMProjectBdFieldLabelLocal_Plex; 5729 dm->ops->computel2diff = DMComputeL2Diff_Plex; 5730 dm->ops->computel2gradientdiff = DMComputeL2GradientDiff_Plex; 5731 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_Plex; 5732 dm->ops->getneighbors = DMGetNeighbors_Plex; 5733 dm->ops->getlocalboundingbox = DMGetLocalBoundingBox_Coordinates; 5734 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex; 5735 dm->ops->createddscatters = DMCreateDomainDecompositionScatters_Plex; 5736 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex)); 5737 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex)); 5738 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex)); 5739 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex)); 5740 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex)); 5741 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex)); 5742 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex)); 5743 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex)); 5744 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex)); 5745 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex)); 5746 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex)); 5747 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex)); 5748 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex)); 5749 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 5750 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex)); 5751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex)); 5752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex)); 5753 PetscFunctionReturn(PETSC_SUCCESS); 5754 } 5755 5756 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm) 5757 { 5758 DM_Plex *mesh = (DM_Plex *)dm->data; 5759 const PetscSF *face_sfs; 5760 PetscInt num_face_sfs; 5761 5762 PetscFunctionBegin; 5763 mesh->refct++; 5764 (*newdm)->data = mesh; 5765 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs)); 5766 PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs)); 5767 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX)); 5768 PetscCall(DMInitialize_Plex(*newdm)); 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 /*MC 5773 DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh (or grid), or CW Complex {cite}`cwcomplex`, 5774 which can be expressed using a Hasse Diagram {cite}`hassediagram`. 5775 In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is 5776 specified by a `PetscSection` object. Ownership in the global representation is determined by 5777 ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object. 5778 5779 Options Database Keys: 5780 + -dm_refine_pre - Refine mesh before distribution 5781 + -dm_refine_uniform_pre - Choose uniform or generator-based refinement 5782 + -dm_refine_volume_limit_pre - Cell volume limit after pre-refinement using generator 5783 . -dm_distribute - Distribute mesh across processes 5784 . -dm_distribute_overlap - Number of cells to overlap for distribution 5785 . -dm_refine - Refine mesh after distribution 5786 . -dm_localize <bool> - Whether to localize coordinates for periodic meshes 5787 . -dm_sparse_localize <bool> - Whether to only localize cells on the periodic boundary 5788 . -dm_plex_hash_location - Use grid hashing for point location 5789 . -dm_plex_hash_box_faces <n,m,p> - The number of divisions in each direction of the grid hash 5790 . -dm_plex_partition_balance - Attempt to evenly divide points on partition boundary between processes 5791 . -dm_plex_remesh_bd - Allow changes to the boundary on remeshing 5792 . -dm_plex_max_projection_height - Maximum mesh point height used to project locally 5793 . -dm_plex_regular_refinement - Use special nested projection algorithm for regular refinement 5794 . -dm_plex_reorder_section - Use specialized blocking if available 5795 . -dm_plex_check_all - Perform all checks below 5796 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric 5797 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices 5798 . -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 5799 . -dm_plex_check_geometry - Check that cells have positive volume 5800 . -dm_view :mesh.tex:ascii_latex - View the mesh in LaTeX/TikZ 5801 . -dm_plex_view_scale <num> - Scale the TikZ 5802 . -dm_plex_print_fem <num> - View FEM assembly information, such as element vectors and matrices 5803 - -dm_plex_print_fvm <num> - View FVM assembly information, such as flux updates 5804 5805 Level: intermediate 5806 5807 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection` 5808 M*/ 5809 5810 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm) 5811 { 5812 DM_Plex *mesh; 5813 PetscInt unit; 5814 5815 PetscFunctionBegin; 5816 PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite)); 5817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5818 PetscCall(PetscNew(&mesh)); 5819 dm->reorderSection = DM_REORDER_DEFAULT_NOTSET; 5820 dm->data = mesh; 5821 5822 mesh->refct = 1; 5823 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection)); 5824 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection)); 5825 mesh->refinementUniform = PETSC_TRUE; 5826 mesh->refinementLimit = -1.0; 5827 mesh->distDefault = PETSC_TRUE; 5828 mesh->reorderDefault = DM_REORDER_DEFAULT_NOTSET; 5829 mesh->distributionName = NULL; 5830 mesh->interpolated = DMPLEX_INTERPOLATED_INVALID; 5831 mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID; 5832 mesh->interpolatePreferTensor = PETSC_TRUE; 5833 5834 PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner)); 5835 mesh->remeshBd = PETSC_FALSE; 5836 5837 for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0; 5838 5839 mesh->depthState = -1; 5840 mesh->celltypeState = -1; 5841 mesh->printTol = 1.0e-10; 5842 mesh->nonempty_comm = MPI_COMM_SELF; 5843 5844 PetscCall(DMInitialize_Plex(dm)); 5845 PetscFunctionReturn(PETSC_SUCCESS); 5846 } 5847 5848 /*@ 5849 DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram. 5850 5851 Collective 5852 5853 Input Parameter: 5854 . comm - The communicator for the `DMPLEX` object 5855 5856 Output Parameter: 5857 . mesh - The `DMPLEX` object 5858 5859 Level: beginner 5860 5861 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()` 5862 @*/ 5863 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh) 5864 { 5865 PetscFunctionBegin; 5866 PetscAssertPointer(mesh, 2); 5867 PetscCall(DMCreate(comm, mesh)); 5868 PetscCall(DMSetType(*mesh, DMPLEX)); 5869 PetscFunctionReturn(PETSC_SUCCESS); 5870 } 5871 5872 /*@C 5873 DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype 5874 5875 Collective; No Fortran Support 5876 5877 Input Parameters: 5878 + dm - The `DM` 5879 . numCells - The number of cells owned by this process 5880 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 5881 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 5882 . numCorners - The number of vertices for each cell 5883 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5884 5885 Output Parameters: 5886 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5887 - verticesAdjSaved - (Optional) vertex adjacency array 5888 5889 Level: advanced 5890 5891 Notes: 5892 Two triangles sharing a face 5893 .vb 5894 5895 2 5896 / | \ 5897 / | \ 5898 / | \ 5899 0 0 | 1 3 5900 \ | / 5901 \ | / 5902 \ | / 5903 1 5904 .ve 5905 would have input 5906 .vb 5907 numCells = 2, numVertices = 4 5908 cells = [0 1 2 1 3 2] 5909 .ve 5910 which would result in the `DMPLEX` 5911 .vb 5912 5913 4 5914 / | \ 5915 / | \ 5916 / | \ 5917 2 0 | 1 5 5918 \ | / 5919 \ | / 5920 \ | / 5921 3 5922 .ve 5923 5924 Vertices are implicitly numbered consecutively 0,...,NVertices. 5925 Each rank owns a chunk of numVertices consecutive vertices. 5926 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 5927 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 5928 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 5929 5930 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 5931 5932 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 5933 `PetscSF` 5934 @*/ 5935 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[]) 5936 { 5937 PetscSF sfPoint; 5938 PetscLayout layout; 5939 PetscInt numVerticesAdj, *verticesAdj, *cones, c, p; 5940 5941 PetscFunctionBegin; 5942 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 5943 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5944 /* Get/check global number of vertices */ 5945 { 5946 PetscInt NVerticesInCells, i; 5947 const PetscInt len = numCells * numCorners; 5948 5949 /* NVerticesInCells = max(cells) + 1 */ 5950 NVerticesInCells = PETSC_INT_MIN; 5951 for (i = 0; i < len; i++) 5952 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5953 ++NVerticesInCells; 5954 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 5955 5956 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 5957 else 5958 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); 5959 } 5960 /* Count locally unique vertices */ 5961 { 5962 PetscHSetI vhash; 5963 PetscInt off = 0; 5964 5965 PetscCall(PetscHSetICreate(&vhash)); 5966 for (c = 0; c < numCells; ++c) { 5967 for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p])); 5968 } 5969 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 5970 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 5971 else verticesAdj = *verticesAdjSaved; 5972 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 5973 PetscCall(PetscHSetIDestroy(&vhash)); 5974 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 5975 } 5976 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 5977 /* Create cones */ 5978 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 5979 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5980 PetscCall(DMSetUp(dm)); 5981 PetscCall(DMPlexGetCones(dm, &cones)); 5982 for (c = 0; c < numCells; ++c) { 5983 for (p = 0; p < numCorners; ++p) { 5984 const PetscInt gv = cells[c * numCorners + p]; 5985 PetscInt lv; 5986 5987 /* Positions within verticesAdj form 0-based local vertex numbering; 5988 we need to shift it by numCells to get correct DAG points (cells go first) */ 5989 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 5990 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 5991 cones[c * numCorners + p] = lv + numCells; 5992 } 5993 } 5994 /* Build point sf */ 5995 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 5996 PetscCall(PetscLayoutSetSize(layout, NVertices)); 5997 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 5998 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 5999 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 6000 PetscCall(PetscLayoutDestroy(&layout)); 6001 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 6002 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 6003 if (dm->sf) { 6004 const char *prefix; 6005 6006 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 6007 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 6008 } 6009 PetscCall(DMSetPointSF(dm, sfPoint)); 6010 PetscCall(PetscSFDestroy(&sfPoint)); 6011 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 6012 /* Fill in the rest of the topology structure */ 6013 PetscCall(DMPlexSymmetrize(dm)); 6014 PetscCall(DMPlexStratify(dm)); 6015 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6016 PetscFunctionReturn(PETSC_SUCCESS); 6017 } 6018 6019 /*@C 6020 DMPlexBuildFromCellSectionParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) allowing multiple celltypes 6021 6022 Collective; No Fortran Support 6023 6024 Input Parameters: 6025 + dm - The `DM` 6026 . numCells - The number of cells owned by this process 6027 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 6028 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 6029 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells) 6030 - cells - An array of the global vertex numbers for each cell 6031 6032 Output Parameters: 6033 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 6034 - verticesAdjSaved - (Optional) vertex adjacency array 6035 6036 Level: advanced 6037 6038 Notes: 6039 A triangle and quadrilateral sharing a face 6040 .vb 6041 2----------3 6042 / | | 6043 / | | 6044 / | | 6045 0 0 | 1 | 6046 \ | | 6047 \ | | 6048 \ | | 6049 1----------4 6050 .ve 6051 would have input 6052 .vb 6053 numCells = 2, numVertices = 5 6054 cells = [0 1 2 1 4 3 2] 6055 .ve 6056 which would result in the `DMPLEX` 6057 .vb 6058 4----------5 6059 / | | 6060 / | | 6061 / | | 6062 2 0 | 1 | 6063 \ | | 6064 \ | | 6065 \ | | 6066 3----------6 6067 .ve 6068 6069 Vertices are implicitly numbered consecutively 0,...,NVertices. 6070 Each rank owns a chunk of numVertices consecutive vertices. 6071 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 6072 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 6073 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 6074 6075 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 6076 6077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexCreateFromCellSectionParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 6078 `PetscSF` 6079 @*/ 6080 PetscErrorCode DMPlexBuildFromCellSectionParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[]) 6081 { 6082 PetscSF sfPoint; 6083 PetscLayout layout; 6084 PetscInt numVerticesAdj, *verticesAdj, *cones, cStart, cEnd, len; 6085 6086 PetscFunctionBegin; 6087 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 6088 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6089 PetscCall(PetscSectionGetChart(cellSection, &cStart, &cEnd)); 6090 PetscCall(PetscSectionGetStorageSize(cellSection, &len)); 6091 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); 6092 /* Get/check global number of vertices */ 6093 { 6094 PetscInt NVerticesInCells; 6095 6096 /* NVerticesInCells = max(cells) + 1 */ 6097 NVerticesInCells = PETSC_MIN_INT; 6098 for (PetscInt i = 0; i < len; i++) 6099 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 6100 ++NVerticesInCells; 6101 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 6102 6103 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 6104 else 6105 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); 6106 } 6107 /* Count locally unique vertices */ 6108 { 6109 PetscHSetI vhash; 6110 PetscInt off = 0; 6111 6112 PetscCall(PetscHSetICreate(&vhash)); 6113 for (PetscInt i = 0; i < len; i++) PetscCall(PetscHSetIAdd(vhash, cells[i])); 6114 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 6115 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 6116 else verticesAdj = *verticesAdjSaved; 6117 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 6118 PetscCall(PetscHSetIDestroy(&vhash)); 6119 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 6120 } 6121 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 6122 /* Create cones */ 6123 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 6124 for (PetscInt c = 0; c < numCells; ++c) { 6125 PetscInt dof; 6126 6127 PetscCall(PetscSectionGetDof(cellSection, c, &dof)); 6128 PetscCall(DMPlexSetConeSize(dm, c, dof)); 6129 } 6130 PetscCall(DMSetUp(dm)); 6131 PetscCall(DMPlexGetCones(dm, &cones)); 6132 for (PetscInt c = 0; c < numCells; ++c) { 6133 PetscInt dof, off; 6134 6135 PetscCall(PetscSectionGetDof(cellSection, c, &dof)); 6136 PetscCall(PetscSectionGetOffset(cellSection, c, &off)); 6137 for (PetscInt p = off; p < off + dof; ++p) { 6138 const PetscInt gv = cells[p]; 6139 PetscInt lv; 6140 6141 /* Positions within verticesAdj form 0-based local vertex numbering; 6142 we need to shift it by numCells to get correct DAG points (cells go first) */ 6143 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 6144 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 6145 cones[p] = lv + numCells; 6146 } 6147 } 6148 /* Build point sf */ 6149 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 6150 PetscCall(PetscLayoutSetSize(layout, NVertices)); 6151 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 6152 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 6153 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 6154 PetscCall(PetscLayoutDestroy(&layout)); 6155 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 6156 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 6157 if (dm->sf) { 6158 const char *prefix; 6159 6160 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 6161 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 6162 } 6163 PetscCall(DMSetPointSF(dm, sfPoint)); 6164 PetscCall(PetscSFDestroy(&sfPoint)); 6165 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 6166 /* Fill in the rest of the topology structure */ 6167 PetscCall(DMPlexSymmetrize(dm)); 6168 PetscCall(DMPlexStratify(dm)); 6169 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6170 PetscFunctionReturn(PETSC_SUCCESS); 6171 } 6172 6173 /*@ 6174 DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 6175 6176 Collective; No Fortran Support 6177 6178 Input Parameters: 6179 + dm - The `DM` 6180 . spaceDim - The spatial dimension used for coordinates 6181 . sfVert - `PetscSF` describing complete vertex ownership 6182 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6183 6184 Level: advanced 6185 6186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()` 6187 @*/ 6188 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[]) 6189 { 6190 PetscSection coordSection; 6191 Vec coordinates; 6192 PetscScalar *coords; 6193 PetscInt numVertices, numVerticesAdj, coordSize, v, vStart, vEnd; 6194 PetscMPIInt spaceDimi; 6195 6196 PetscFunctionBegin; 6197 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6198 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6199 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 6200 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 6201 PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL)); 6202 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); 6203 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6204 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6205 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 6206 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 6207 for (v = vStart; v < vEnd; ++v) { 6208 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 6209 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 6210 } 6211 PetscCall(PetscSectionSetUp(coordSection)); 6212 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6213 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates)); 6214 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 6215 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6216 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6217 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6218 PetscCall(VecGetArray(coordinates, &coords)); 6219 { 6220 MPI_Datatype coordtype; 6221 6222 /* Need a temp buffer for coords if we have complex/single */ 6223 PetscCall(PetscMPIIntCast(spaceDim, &spaceDimi)); 6224 PetscCallMPI(MPI_Type_contiguous(spaceDimi, MPIU_SCALAR, &coordtype)); 6225 PetscCallMPI(MPI_Type_commit(&coordtype)); 6226 #if defined(PETSC_USE_COMPLEX) 6227 { 6228 PetscScalar *svertexCoords; 6229 PetscInt i; 6230 PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords)); 6231 for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i]; 6232 PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 6233 PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 6234 PetscCall(PetscFree(svertexCoords)); 6235 } 6236 #else 6237 PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 6238 PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 6239 #endif 6240 PetscCallMPI(MPI_Type_free(&coordtype)); 6241 } 6242 PetscCall(VecRestoreArray(coordinates, &coords)); 6243 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6244 PetscCall(VecDestroy(&coordinates)); 6245 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6246 PetscFunctionReturn(PETSC_SUCCESS); 6247 } 6248 6249 /*@ 6250 DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype 6251 6252 Collective 6253 6254 Input Parameters: 6255 + comm - The communicator 6256 . dim - The topological dimension of the mesh 6257 . numCells - The number of cells owned by this process 6258 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 6259 . NVertices - The global number of vertices, or `PETSC_DECIDE` 6260 . numCorners - The number of vertices for each cell 6261 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 6262 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 6263 . spaceDim - The spatial dimension used for coordinates 6264 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6265 6266 Output Parameters: 6267 + dm - The `DM` 6268 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 6269 - verticesAdj - (Optional) vertex adjacency array 6270 6271 Level: intermediate 6272 6273 Notes: 6274 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 6275 `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 6276 6277 See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters. 6278 6279 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 6280 6281 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 6282 @*/ 6283 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) 6284 { 6285 PetscSF sfVert; 6286 6287 PetscFunctionBegin; 6288 PetscCall(DMCreate(comm, dm)); 6289 PetscCall(DMSetType(*dm, DMPLEX)); 6290 PetscValidLogicalCollectiveInt(*dm, dim, 2); 6291 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 6292 PetscCall(DMSetDimension(*dm, dim)); 6293 PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj)); 6294 if (interpolate) { 6295 DM idm; 6296 6297 PetscCall(DMPlexInterpolate(*dm, &idm)); 6298 PetscCall(DMDestroy(dm)); 6299 *dm = idm; 6300 } 6301 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 6302 if (vertexSF) *vertexSF = sfVert; 6303 else PetscCall(PetscSFDestroy(&sfVert)); 6304 PetscFunctionReturn(PETSC_SUCCESS); 6305 } 6306 6307 /*@ 6308 DMPlexCreateFromCellSectionParallel - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) and supports multiple celltypes 6309 6310 Collective 6311 6312 Input Parameters: 6313 + comm - The communicator 6314 . dim - The topological dimension of the mesh 6315 . numCells - The number of cells owned by this process 6316 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 6317 . NVertices - The global number of vertices, or `PETSC_DECIDE` 6318 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells) 6319 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 6320 . cells - An array of the global vertex numbers for each cell 6321 . spaceDim - The spatial dimension used for coordinates 6322 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6323 6324 Output Parameters: 6325 + dm - The `DM` 6326 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 6327 - verticesAdj - (Optional) vertex adjacency array 6328 6329 Level: intermediate 6330 6331 Notes: 6332 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 6333 `DMPlexBuildFromCellSectionParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 6334 6335 See `DMPlexBuildFromCellSectionParallel()` for an example and details about the topology-related parameters. 6336 6337 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 6338 6339 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 6340 @*/ 6341 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) 6342 { 6343 PetscSF sfVert; 6344 6345 PetscFunctionBegin; 6346 PetscCall(DMCreate(comm, dm)); 6347 PetscCall(DMSetType(*dm, DMPLEX)); 6348 PetscValidLogicalCollectiveInt(*dm, dim, 2); 6349 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 6350 PetscCall(DMSetDimension(*dm, dim)); 6351 PetscCall(DMPlexBuildFromCellSectionParallel(*dm, numCells, numVertices, NVertices, cellSection, cells, &sfVert, verticesAdj)); 6352 if (interpolate) { 6353 DM idm; 6354 6355 PetscCall(DMPlexInterpolate(*dm, &idm)); 6356 PetscCall(DMDestroy(dm)); 6357 *dm = idm; 6358 } 6359 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 6360 if (vertexSF) *vertexSF = sfVert; 6361 else PetscCall(PetscSFDestroy(&sfVert)); 6362 PetscFunctionReturn(PETSC_SUCCESS); 6363 } 6364 6365 /*@ 6366 DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 6367 6368 Collective; No Fortran Support 6369 6370 Input Parameters: 6371 + dm - The `DM` 6372 . numCells - The number of cells owned by this process 6373 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE` 6374 . numCorners - The number of vertices for each cell 6375 - cells - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell 6376 6377 Level: advanced 6378 6379 Notes: 6380 Two triangles sharing a face 6381 .vb 6382 6383 2 6384 / | \ 6385 / | \ 6386 / | \ 6387 0 0 | 1 3 6388 \ | / 6389 \ | / 6390 \ | / 6391 1 6392 .ve 6393 would have input 6394 .vb 6395 numCells = 2, numVertices = 4 6396 cells = [0 1 2 1 3 2] 6397 .ve 6398 which would result in the `DMPLEX` 6399 .vb 6400 6401 4 6402 / | \ 6403 / | \ 6404 / | \ 6405 2 0 | 1 5 6406 \ | / 6407 \ | / 6408 \ | / 6409 3 6410 .ve 6411 6412 If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1. 6413 6414 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()` 6415 @*/ 6416 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[]) 6417 { 6418 PetscInt *cones, c, p, dim; 6419 6420 PetscFunctionBegin; 6421 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6422 PetscCall(DMGetDimension(dm, &dim)); 6423 /* Get/check global number of vertices */ 6424 { 6425 PetscInt NVerticesInCells, i; 6426 const PetscInt len = numCells * numCorners; 6427 6428 /* NVerticesInCells = max(cells) + 1 */ 6429 NVerticesInCells = PETSC_INT_MIN; 6430 for (i = 0; i < len; i++) 6431 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 6432 ++NVerticesInCells; 6433 6434 if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells; 6435 else 6436 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); 6437 } 6438 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 6439 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 6440 PetscCall(DMSetUp(dm)); 6441 PetscCall(DMPlexGetCones(dm, &cones)); 6442 for (c = 0; c < numCells; ++c) { 6443 for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells; 6444 } 6445 PetscCall(DMPlexSymmetrize(dm)); 6446 PetscCall(DMPlexStratify(dm)); 6447 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6448 PetscFunctionReturn(PETSC_SUCCESS); 6449 } 6450 6451 /*@ 6452 DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 6453 6454 Collective 6455 6456 Input Parameters: 6457 + dm - The `DM` 6458 . spaceDim - The spatial dimension used for coordinates 6459 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6460 6461 Level: advanced 6462 6463 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()` 6464 @*/ 6465 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[]) 6466 { 6467 PetscSection coordSection; 6468 Vec coordinates; 6469 DM cdm; 6470 PetscScalar *coords; 6471 PetscInt v, vStart, vEnd, d; 6472 6473 PetscFunctionBegin; 6474 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6475 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6476 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 6477 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 6478 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6479 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6480 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 6481 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 6482 for (v = vStart; v < vEnd; ++v) { 6483 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 6484 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 6485 } 6486 PetscCall(PetscSectionSetUp(coordSection)); 6487 6488 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6489 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 6490 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 6491 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6492 PetscCall(VecGetArrayWrite(coordinates, &coords)); 6493 for (v = 0; v < vEnd - vStart; ++v) { 6494 for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d]; 6495 } 6496 PetscCall(VecRestoreArrayWrite(coordinates, &coords)); 6497 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6498 PetscCall(VecDestroy(&coordinates)); 6499 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6500 PetscFunctionReturn(PETSC_SUCCESS); 6501 } 6502 6503 /*@ 6504 DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input 6505 6506 Collective 6507 6508 Input Parameters: 6509 + comm - The communicator 6510 . dim - The topological dimension of the mesh 6511 . numCells - The number of cells, only on process 0 6512 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0 6513 . numCorners - The number of vertices for each cell, only on process 0 6514 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 6515 . cells - An array of $ numCells \times numCorners$ numbers, the vertices for each cell, only on process 0 6516 . spaceDim - The spatial dimension used for coordinates 6517 - vertexCoords - An array of $ numVertices \times spaceDim$ numbers, the coordinates of each vertex, only on process 0 6518 6519 Output Parameter: 6520 . dm - The `DM`, which only has points on process 0 6521 6522 Level: intermediate 6523 6524 Notes: 6525 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`, 6526 `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()` 6527 6528 See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters. 6529 See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters. 6530 See `DMPlexCreateFromCellListParallelPetsc()` for parallel input 6531 6532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 6533 @*/ 6534 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) 6535 { 6536 PetscMPIInt rank; 6537 6538 PetscFunctionBegin; 6539 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."); 6540 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6541 PetscCall(DMCreate(comm, dm)); 6542 PetscCall(DMSetType(*dm, DMPLEX)); 6543 PetscCall(DMSetDimension(*dm, dim)); 6544 if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells)); 6545 else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL)); 6546 if (interpolate) { 6547 DM idm; 6548 6549 PetscCall(DMPlexInterpolate(*dm, &idm)); 6550 PetscCall(DMDestroy(dm)); 6551 *dm = idm; 6552 } 6553 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords)); 6554 else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL)); 6555 PetscFunctionReturn(PETSC_SUCCESS); 6556 } 6557 6558 /*@ 6559 DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM` 6560 6561 Input Parameters: 6562 + dm - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()` 6563 . depth - The depth of the DAG 6564 . numPoints - Array of size $ depth + 1 $ containing the number of points at each `depth` 6565 . coneSize - The cone size of each point 6566 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point 6567 . coneOrientations - The orientation of each cone point 6568 - vertexCoords - An array of $ numPoints[0] \times spacedim $ numbers representing the coordinates of each vertex, with `spacedim` the value set via `DMSetCoordinateDim()` 6569 6570 Output Parameter: 6571 . dm - The `DM` 6572 6573 Level: advanced 6574 6575 Note: 6576 Two triangles sharing a face would have input 6577 .vb 6578 depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0] 6579 cones = [2 3 4 3 5 4], coneOrientations = [0 0 0 0 0 0] 6580 vertexCoords = [-1.0 0.0 0.0 -1.0 0.0 1.0 1.0 0.0] 6581 .ve 6582 which would result in the DMPlex 6583 .vb 6584 4 6585 / | \ 6586 / | \ 6587 / | \ 6588 2 0 | 1 5 6589 \ | / 6590 \ | / 6591 \ | / 6592 3 6593 .ve 6594 Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()` 6595 6596 Developer Note: 6597 This does not create anything so should not have create in the name. 6598 6599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 6600 @*/ 6601 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[]) 6602 { 6603 Vec coordinates; 6604 PetscSection coordSection; 6605 PetscScalar *coords; 6606 PetscInt coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off; 6607 6608 PetscFunctionBegin; 6609 PetscCall(DMGetDimension(dm, &dim)); 6610 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 6611 PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim); 6612 for (d = 0; d <= depth; ++d) pEnd += numPoints[d]; 6613 PetscCall(DMPlexSetChart(dm, pStart, pEnd)); 6614 for (p = pStart; p < pEnd; ++p) { 6615 PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart])); 6616 if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart; 6617 } 6618 PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]); 6619 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 6620 for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) { 6621 PetscCall(DMPlexSetCone(dm, p, &cones[off])); 6622 PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off])); 6623 } 6624 PetscCall(DMPlexSymmetrize(dm)); 6625 PetscCall(DMPlexStratify(dm)); 6626 /* Build coordinates */ 6627 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6628 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6629 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed)); 6630 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0])); 6631 for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) { 6632 PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed)); 6633 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed)); 6634 } 6635 PetscCall(PetscSectionSetUp(coordSection)); 6636 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6637 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 6638 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6639 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6640 PetscCall(VecSetBlockSize(coordinates, PetscMax(dimEmbed, 1))); 6641 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6642 if (vertexCoords) { 6643 PetscCall(VecGetArray(coordinates, &coords)); 6644 for (v = 0; v < numPoints[0]; ++v) { 6645 PetscInt off; 6646 6647 PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off)); 6648 for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d]; 6649 } 6650 } 6651 PetscCall(VecRestoreArray(coordinates, &coords)); 6652 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6653 PetscCall(VecDestroy(&coordinates)); 6654 PetscFunctionReturn(PETSC_SUCCESS); 6655 } 6656 6657 /* 6658 DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file. 6659 6660 Collective 6661 6662 + comm - The MPI communicator 6663 . filename - Name of the .dat file 6664 - interpolate - Create faces and edges in the mesh 6665 6666 Output Parameter: 6667 . dm - The `DM` object representing the mesh 6668 6669 Level: beginner 6670 6671 Note: 6672 The format is the simplest possible: 6673 .vb 6674 dim Ne Nv Nc Nl 6675 v_1 v_2 ... v_Nc 6676 ... 6677 x y z marker_1 ... marker_Nl 6678 .ve 6679 6680 Developer Note: 6681 Should use a `PetscViewer` not a filename 6682 6683 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()` 6684 */ 6685 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 6686 { 6687 DMLabel marker; 6688 PetscViewer viewer; 6689 Vec coordinates; 6690 PetscSection coordSection; 6691 PetscScalar *coords; 6692 char line[PETSC_MAX_PATH_LEN]; 6693 PetscInt cdim, coordSize, v, c, d; 6694 PetscMPIInt rank; 6695 int snum, dim, Nv, Nc, Ncn, Nl; 6696 6697 PetscFunctionBegin; 6698 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6699 PetscCall(PetscViewerCreate(comm, &viewer)); 6700 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII)); 6701 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 6702 PetscCall(PetscViewerFileSetName(viewer, filename)); 6703 if (rank == 0) { 6704 PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING)); 6705 snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl); 6706 PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6707 } else { 6708 Nc = Nv = Ncn = Nl = 0; 6709 } 6710 PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm)); 6711 cdim = dim; 6712 PetscCall(DMCreate(comm, dm)); 6713 PetscCall(DMSetType(*dm, DMPLEX)); 6714 PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv)); 6715 PetscCall(DMSetDimension(*dm, dim)); 6716 PetscCall(DMSetCoordinateDim(*dm, cdim)); 6717 /* Read topology */ 6718 if (rank == 0) { 6719 char format[PETSC_MAX_PATH_LEN]; 6720 PetscInt cone[8]; 6721 int vbuf[8], v; 6722 6723 for (c = 0; c < Ncn; ++c) { 6724 format[c * 3 + 0] = '%'; 6725 format[c * 3 + 1] = 'd'; 6726 format[c * 3 + 2] = ' '; 6727 } 6728 format[Ncn * 3 - 1] = '\0'; 6729 for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn)); 6730 PetscCall(DMSetUp(*dm)); 6731 for (c = 0; c < Nc; ++c) { 6732 PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING)); 6733 switch (Ncn) { 6734 case 2: 6735 snum = sscanf(line, format, &vbuf[0], &vbuf[1]); 6736 break; 6737 case 3: 6738 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]); 6739 break; 6740 case 4: 6741 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]); 6742 break; 6743 case 6: 6744 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]); 6745 break; 6746 case 8: 6747 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]); 6748 break; 6749 default: 6750 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn); 6751 } 6752 PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6753 for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc; 6754 /* Hexahedra are inverted */ 6755 if (Ncn == 8) { 6756 PetscInt tmp = cone[1]; 6757 cone[1] = cone[3]; 6758 cone[3] = tmp; 6759 } 6760 PetscCall(DMPlexSetCone(*dm, c, cone)); 6761 } 6762 } 6763 PetscCall(DMPlexSymmetrize(*dm)); 6764 PetscCall(DMPlexStratify(*dm)); 6765 /* Read coordinates */ 6766 PetscCall(DMGetCoordinateSection(*dm, &coordSection)); 6767 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6768 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 6769 PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv)); 6770 for (v = Nc; v < Nc + Nv; ++v) { 6771 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 6772 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 6773 } 6774 PetscCall(PetscSectionSetUp(coordSection)); 6775 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6776 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 6777 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6778 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6779 PetscCall(VecSetBlockSize(coordinates, cdim)); 6780 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6781 PetscCall(VecGetArray(coordinates, &coords)); 6782 if (rank == 0) { 6783 char format[PETSC_MAX_PATH_LEN]; 6784 double x[3]; 6785 int l, val[3]; 6786 6787 if (Nl) { 6788 for (l = 0; l < Nl; ++l) { 6789 format[l * 3 + 0] = '%'; 6790 format[l * 3 + 1] = 'd'; 6791 format[l * 3 + 2] = ' '; 6792 } 6793 format[Nl * 3 - 1] = '\0'; 6794 PetscCall(DMCreateLabel(*dm, "marker")); 6795 PetscCall(DMGetLabel(*dm, "marker", &marker)); 6796 } 6797 for (v = 0; v < Nv; ++v) { 6798 PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING)); 6799 snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]); 6800 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6801 switch (Nl) { 6802 case 0: 6803 snum = 0; 6804 break; 6805 case 1: 6806 snum = sscanf(line, format, &val[0]); 6807 break; 6808 case 2: 6809 snum = sscanf(line, format, &val[0], &val[1]); 6810 break; 6811 case 3: 6812 snum = sscanf(line, format, &val[0], &val[1], &val[2]); 6813 break; 6814 default: 6815 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl); 6816 } 6817 PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6818 for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d]; 6819 for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l])); 6820 } 6821 } 6822 PetscCall(VecRestoreArray(coordinates, &coords)); 6823 PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 6824 PetscCall(VecDestroy(&coordinates)); 6825 PetscCall(PetscViewerDestroy(&viewer)); 6826 if (interpolate) { 6827 DM idm; 6828 DMLabel bdlabel; 6829 6830 PetscCall(DMPlexInterpolate(*dm, &idm)); 6831 PetscCall(DMDestroy(dm)); 6832 *dm = idm; 6833 6834 if (!Nl) { 6835 PetscCall(DMCreateLabel(*dm, "marker")); 6836 PetscCall(DMGetLabel(*dm, "marker", &bdlabel)); 6837 PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel)); 6838 PetscCall(DMPlexLabelComplete(*dm, bdlabel)); 6839 } 6840 } 6841 PetscFunctionReturn(PETSC_SUCCESS); 6842 } 6843 6844 /*@ 6845 DMPlexCreateFromFile - This takes a filename and produces a `DM` 6846 6847 Collective 6848 6849 Input Parameters: 6850 + comm - The communicator 6851 . filename - A file name 6852 . plexname - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats 6853 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 6854 6855 Output Parameter: 6856 . dm - The `DM` 6857 6858 Options Database Key: 6859 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5 6860 6861 Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. `-dm_plex_create_viewer_hdf5_collective` 6862 6863 Level: beginner 6864 6865 Notes: 6866 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 6867 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 6868 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 6869 The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally 6870 calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats. 6871 6872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()` 6873 @*/ 6874 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm) 6875 { 6876 const char extGmsh[] = ".msh"; 6877 const char extGmsh2[] = ".msh2"; 6878 const char extGmsh4[] = ".msh4"; 6879 const char extCGNS[] = ".cgns"; 6880 const char extExodus[] = ".exo"; 6881 const char extExodus_e[] = ".e"; 6882 const char extGenesis[] = ".gen"; 6883 const char extFluent[] = ".cas"; 6884 const char extHDF5[] = ".h5"; 6885 const char extXDMFHDF5[] = ".xdmf.h5"; 6886 const char extPLY[] = ".ply"; 6887 const char extEGADSlite[] = ".egadslite"; 6888 const char extEGADS[] = ".egads"; 6889 const char extIGES[] = ".igs"; 6890 const char extIGES2[] = ".iges"; 6891 const char extSTEP[] = ".stp"; 6892 const char extSTEP2[] = ".step"; 6893 const char extBREP[] = ".brep"; 6894 const char extCV[] = ".dat"; 6895 size_t len; 6896 PetscBool isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSlite, isEGADS, isIGES, isIGES2, isSTEP, isSTEP2, isBREP, isCV, isXDMFHDF5; 6897 PetscMPIInt rank; 6898 6899 PetscFunctionBegin; 6900 PetscAssertPointer(filename, 2); 6901 if (plexname) PetscAssertPointer(plexname, 3); 6902 PetscAssertPointer(dm, 5); 6903 PetscCall(DMInitializePackage()); 6904 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 6905 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6906 PetscCall(PetscStrlen(filename, &len)); 6907 PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path"); 6908 6909 #define CheckExtension(extension__, is_extension__) \ 6910 do { \ 6911 PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \ 6912 /* don't count the null-terminator at the end */ \ 6913 const size_t ext_len = sizeof(extension__) - 1; \ 6914 if (len < ext_len) { \ 6915 is_extension__ = PETSC_FALSE; \ 6916 } else { \ 6917 PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \ 6918 } \ 6919 } while (0) 6920 6921 CheckExtension(extGmsh, isGmsh); 6922 CheckExtension(extGmsh2, isGmsh2); 6923 CheckExtension(extGmsh4, isGmsh4); 6924 CheckExtension(extCGNS, isCGNS); 6925 CheckExtension(extExodus, isExodus); 6926 if (!isExodus) CheckExtension(extExodus_e, isExodus); 6927 CheckExtension(extGenesis, isGenesis); 6928 CheckExtension(extFluent, isFluent); 6929 CheckExtension(extHDF5, isHDF5); 6930 CheckExtension(extPLY, isPLY); 6931 CheckExtension(extEGADSlite, isEGADSlite); 6932 CheckExtension(extEGADS, isEGADS); 6933 CheckExtension(extIGES, isIGES); 6934 CheckExtension(extIGES2, isIGES2); 6935 CheckExtension(extSTEP, isSTEP); 6936 CheckExtension(extSTEP2, isSTEP2); 6937 CheckExtension(extBREP, isBREP); 6938 CheckExtension(extCV, isCV); 6939 CheckExtension(extXDMFHDF5, isXDMFHDF5); 6940 6941 #undef CheckExtension 6942 6943 if (isGmsh || isGmsh2 || isGmsh4) { 6944 PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm)); 6945 } else if (isCGNS) { 6946 PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm)); 6947 } else if (isExodus || isGenesis) { 6948 PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm)); 6949 } else if (isFluent) { 6950 PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm)); 6951 } else if (isHDF5) { 6952 PetscViewer viewer; 6953 6954 /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */ 6955 PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL)); 6956 PetscCall(PetscViewerCreate(comm, &viewer)); 6957 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5)); 6958 PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_")); 6959 PetscCall(PetscViewerSetFromOptions(viewer)); 6960 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 6961 PetscCall(PetscViewerFileSetName(viewer, filename)); 6962 6963 PetscCall(DMCreate(comm, dm)); 6964 PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 6965 PetscCall(DMSetType(*dm, DMPLEX)); 6966 if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF)); 6967 PetscCall(DMLoad(*dm, viewer)); 6968 if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer)); 6969 PetscCall(PetscViewerDestroy(&viewer)); 6970 6971 if (interpolate) { 6972 DM idm; 6973 6974 PetscCall(DMPlexInterpolate(*dm, &idm)); 6975 PetscCall(DMDestroy(dm)); 6976 *dm = idm; 6977 } 6978 } else if (isPLY) { 6979 PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm)); 6980 } else if (isEGADSlite || isEGADS || isIGES || isIGES2 || isSTEP || isSTEP2 || isBREP) { 6981 PetscCall(DMPlexCreateGeomFromFile(comm, filename, dm, isEGADSlite)); 6982 6983 if (!interpolate) { 6984 DM udm; 6985 6986 PetscCall(DMPlexUninterpolate(*dm, &udm)); 6987 PetscCall(DMDestroy(dm)); 6988 *dm = udm; 6989 } 6990 } else if (isCV) { 6991 PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm)); 6992 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename); 6993 PetscCall(PetscStrlen(plexname, &len)); 6994 if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 6995 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 6996 PetscFunctionReturn(PETSC_SUCCESS); 6997 } 6998 6999 /*@ 7000 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. 7001 7002 Input Parameters: 7003 + tr - The `DMPlexTransform` 7004 - prefix - An options prefix, or NULL 7005 7006 Output Parameter: 7007 . dm - The `DM` 7008 7009 Level: beginner 7010 7011 Notes: 7012 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. 7013 7014 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 7015 @*/ 7016 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm) 7017 { 7018 DM bdm, bcdm, cdm; 7019 Vec coordinates, coordinatesNew; 7020 PetscSection cs; 7021 PetscInt cdim, Nl; 7022 7023 PetscFunctionBegin; 7024 PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm)); 7025 PetscCall(DMSetType(*dm, DMPLEX)); 7026 ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL; 7027 // Handle coordinates 7028 PetscCall(DMPlexTransformGetDM(tr, &bdm)); 7029 PetscCall(DMPlexTransformSetDimensions(tr, bdm, *dm)); 7030 PetscCall(DMGetCoordinateDim(*dm, &cdim)); 7031 PetscCall(DMGetCoordinateDM(bdm, &bcdm)); 7032 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 7033 PetscCall(DMCopyDisc(bcdm, cdm)); 7034 PetscCall(DMGetLocalSection(cdm, &cs)); 7035 PetscCall(PetscSectionSetNumFields(cs, 1)); 7036 PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim)); 7037 PetscCall(DMGetCoordinatesLocal(bdm, &coordinates)); 7038 PetscCall(VecDuplicate(coordinates, &coordinatesNew)); 7039 PetscCall(VecCopy(coordinates, coordinatesNew)); 7040 PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew)); 7041 PetscCall(VecDestroy(&coordinatesNew)); 7042 7043 PetscCall(PetscObjectReference((PetscObject)tr)); 7044 PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr)); 7045 ((DM_Plex *)(*dm)->data)->tr = tr; 7046 PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE)); 7047 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix)); 7048 PetscCall(DMSetFromOptions(*dm)); 7049 7050 PetscCall(DMGetNumLabels(bdm, &Nl)); 7051 for (PetscInt l = 0; l < Nl; ++l) { 7052 DMLabel label, labelNew; 7053 const char *lname; 7054 PetscBool isDepth, isCellType; 7055 7056 PetscCall(DMGetLabelName(bdm, l, &lname)); 7057 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 7058 if (isDepth) continue; 7059 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 7060 if (isCellType) continue; 7061 PetscCall(DMCreateLabel(*dm, lname)); 7062 PetscCall(DMGetLabel(bdm, lname, &label)); 7063 PetscCall(DMGetLabel(*dm, lname, &labelNew)); 7064 PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL)); 7065 PetscCall(DMLabelEphemeralSetLabel(labelNew, label)); 7066 PetscCall(DMLabelEphemeralSetTransform(labelNew, tr)); 7067 PetscCall(DMLabelSetUp(labelNew)); 7068 } 7069 PetscFunctionReturn(PETSC_SUCCESS); 7070 } 7071